From: Simon Forman
Date: Sat, 27 Nov 2021 17:04:25 +0000 (-0800)
Subject: Recover the square spiral example code.
X-Git-Url: http://git.osdn.net/view?p=joypy%2FThun.git;a=commitdiff_plain;h=1b193b19243a3aa23f74b6ecbcfd3f217bf66907
Recover the square spiral example code.
I hve no idea how this isn't in VCS. I checked hg and git. Is it in
an old branch that I deleted before merging or something? I have
backups from which to restore, but it would be nice to know how I effed
it up in the first place, eh?
---
diff --git a/docs/Square_Spiral.html b/docs/Square_Spiral.html
new file mode 100644
index 0000000..7a94974
--- /dev/null
+++ b/docs/Square_Spiral.html
@@ -0,0 +1,13739 @@
+
+
+
+
+Square_Spiral
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Square Spiral Example Joy Code¶
+
+
+
+
+
+
+
Here is the example of Joy code from the README
file:
+
+
[[[abs]ii <=][[<>][pop !-]||]&&][[!-][[++]][[--]]ifte dip][[pop !-][--][++]ifte]ifte
+
+
+
It might seem unreadable but with a little familiarity it becomes just as
+legible as any other notation. Some layout helps:
+
+
[ [[abs] ii <=]
+ [
+ [<>] [pop !-] ||
+ ] &&
+]
+[[ !-] [[++]] [[--]] ifte dip]
+[[pop !-] [--] [++] ifte ]
+ifte
+
+
+
This function accepts two integers on the stack and increments or
+decrements one of them such that the new pair of numbers is the next
+coordinate pair in a square spiral (like the kind used to construct an
+Ulam Spiral).
+
+
+
+
+
+
+
+
It's adapted from the original code on StackOverflow :
+
If all you're trying to do is generate the first N points in the spiral
+(without the original problem's constraint of masking to an N x M
+region), the code becomes very simple:
+
+
+
void spiral(const int N)
+{
+ int x = 0;
+ int y = 0;
+ for(int i = 0; i < N; ++i)
+ {
+ cout << x << '\t' << y << '\n';
+ if(abs(x) <= abs(y) && (x != y || x >= 0))
+ x += ((y >= 0) ? 1 : -1);
+ else
+ y += ((x >= 0) ? -1 : 1);
+ }
+}
+
+
+
+
+
+
+
+
Translation to Joy¶ I'm going to make a function that take two ints (x
and y
) and
+generates the next pair, we'll turn it into a generator later using the
+x
combinator.
+
+
+
+
+
+
+
+
First Boolean Predicate¶ We need a function that computes abs(x) <= abs(y)
, we can use ii
to
+apply abs
to both values and then compare them
+with <=
:
+
+
[abs] ii <=
+
+
+
I've defined two short-circuiting Boolean combinators &&
and ||
that
+each accept two quoted predicate programs, run the first, and
+conditionally run the second only if required (to compute the final
+Boolean value). They run their predicate arguments nullary
.
+
+
+
+
+
+
+
+
+
Given those, we can define x != y || x >= 0
as:
+
+
[<>] [pop 0 >=] ||
+
+
+
And (abs(x) <= abs(y) && (x != y || x >= 0))
as:
+
+
[[abs] ii <=] [[<>] [pop 0 >=] ||] &&
+
+
+
It's a little rough, but, as I say, with a little familiarity it becomes
+legible.
+
+
+
+
+
+
+
+
The Increment / Decrement Branches¶ Turning to the branches of the main if
statement:
+
+
x += ((y >= 0) ? 1 : -1);
+
+
+
Rewrite as a hybrid (pseudo-code) ifte
expression:
+
+
[y >= 0] [x += 1] [X -= 1] ifte
+
+
+
Change each C phrase to Joy code:
+
+
[0 >=] [[++] dip] [[--] dip] ifte
+
+
+
Factor out the dip from each branch:
+
+
[0 >=] [[++]] [[--]] ifte dip
+
+
+
Similar logic applies to the other branch:
+
+
y += ((x >= 0) ? -1 : 1);
+
+[x >= 0] [y -= 1] [y += 1] ifte
+
+[pop 0 >=] [--] [++] ifte
+
+
+
+
+
+
+
+
+
+
Putting the Pieces Together¶ We can assemble the three functions we just defined in quotes and give
+them them to the ifte
combinator. With some arrangement to show off
+the symmetry of the two branches, we have:
+
+
[[[abs] ii <=] [[<>] [pop !-] ||] &&]
+[[ !-] [[++]] [[--]] ifte dip]
+[[pop !-] [--] [++] ifte ]
+ifte
+
+
+
As I was writing this up I realized that, since the &&
combinator
+doesn't consume the stack (below its quoted args), I can unquote the
+predicate, swap the branches, and use the branch
combinator instead of
+ifte
:
+
+
[[abs] ii <=] [[<>] [pop !-] ||] &&
+[[pop !-] [--] [++] ifte ]
+[[ !-] [[++]] [[--]] ifte dip]
+branch
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Turning it into a Generator with x
¶ It can be used with the x combinator to make a kind of generator for
+spiral square coordinates.
+
We can use codireco
to make a generator
+
+
codireco ::= cons dip rest cons
+
+
+
It will look like this:
+
+
[value [F] codireco]
+
+
+
Here's a trace of how it works:
+
+
[0 [dup ++] codireco] . x
+ [0 [dup ++] codireco] . 0 [dup ++] codireco
+ [0 [dup ++] codireco] 0 . [dup ++] codireco
+[0 [dup ++] codireco] 0 [dup ++] . codireco
+[0 [dup ++] codireco] 0 [dup ++] . cons dip rest cons
+[0 [dup ++] codireco] [0 dup ++] . dip rest cons
+ . 0 dup ++ [0 [dup ++] codireco] rest cons
+ 0 . dup ++ [0 [dup ++] codireco] rest cons
+ 0 0 . ++ [0 [dup ++] codireco] rest cons
+ 0 1 . [0 [dup ++] codireco] rest cons
+ 0 1 [0 [dup ++] codireco] . rest cons
+ 0 1 [[dup ++] codireco] . cons
+ 0 [1 [dup ++] codireco] .
+
+
+
+
+
+
+
+
But first we have to change the spiral_next
function to work on a
+quoted pair of integers, and leave a copy of the pair on the stack.
+From:
+
+
y x spiral_next
+---------------------
+ y' x'
+
+
+
to:
+
+
[x y] [spiral_next] infra
+-------------------------------
+ [x' y']
+
+
+
+
+
+
+
+
+
So our generator is:
+
+
[[x y] [dup [spiral_next] infra] codireco]
+
+
+
Or rather:
+
+
[[0 0] [dup [spiral_next] infra] codireco]
+
+
+
There is a function make_generator
that will build the generator for us
+out of the value and stepper function:
+
+
[0 0] [dup [spiral_next] infra] make_generator
+----------------------------------------------------
+ [[0 0] [dup [spiral_next] infra] codireco]
+
+
+
+
+
+
+
+
Here it is in action:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
[0 0] [0 1] [-1 1] [-1 0]
+
+
+
+
+
+
+
+
+
+
+
+
Four x
combinators, four pairs of coordinates.
+
+
+
+
+
+
+
+
Conclusion¶ So that's an example of Joy code. It's a straightforward translation of
+the original. It's a little long for a single definition, you might
+break it up like so:
+
+
_spn_P ::= [[abs] ii <=] [[<>] [pop !-] ||] &&
+
+ _spn_T ::= [ !-] [[++]] [[--]] ifte dip
+ _spn_E ::= [pop !-] [--] [++] ifte
+
+spiral_next ::= _spn_P [_spn_E] [_spn_T] branch
+
+
+
This way it's easy to see that the function is a branch with two
+quasi-symmetrical paths.
+
We then used this function to make a simple generator of coordinate
+pairs, where the next pair in the series can be generated at any time by
+using the x
combinator on the generator (which is just a quoted
+expression containing a copy of the current pair and the "stepper
+function" to generate the next pair from that.)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
. 23 18 spiral_next
+ 23 . 18 spiral_next
+ 23 18 . spiral_next
+ 23 18 . _spn_P [_spn_E] [_spn_T] branch
+ 23 18 . [[abs] ii <=] [[<>] [pop !-] ||] && [_spn_E] [_spn_T] branch
+ 23 18 [[abs] ii <=] . [[<>] [pop !-] ||] && [_spn_E] [_spn_T] branch
+ 23 18 [[abs] ii <=] [[<>] [pop !-] ||] . && [_spn_E] [_spn_T] branch
+ 23 18 [[abs] ii <=] [[<>] [pop !-] ||] . [nullary] cons [nullary [0]] dip branch [_spn_E] [_spn_T] branch
+ 23 18 [[abs] ii <=] [[<>] [pop !-] ||] [nullary] . cons [nullary [0]] dip branch [_spn_E] [_spn_T] branch
+ 23 18 [[abs] ii <=] [[[<>] [pop !-] ||] nullary] . [nullary [0]] dip branch [_spn_E] [_spn_T] branch
+23 18 [[abs] ii <=] [[[<>] [pop !-] ||] nullary] [nullary [0]] . dip branch [_spn_E] [_spn_T] branch
+ 23 18 [[abs] ii <=] . nullary [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 [[abs] ii <=] . [stack] dinfrirst [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 [[abs] ii <=] [stack] . dinfrirst [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 [[abs] ii <=] [stack] . dip infra first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 . stack [[abs] ii <=] infra first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 [18 23] . [[abs] ii <=] infra first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 [18 23] [[abs] ii <=] . infra first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 . [abs] ii <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 [abs] . ii <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 [abs] . [dip] dupdip i <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 [abs] [dip] . dupdip i <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 [abs] . dip [abs] i <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 . abs 18 [abs] i <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 . 18 [abs] i <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 . [abs] i <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 [abs] . i <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 . abs <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 . <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ False . [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ False [18 23] . swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 [False] . first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 False . [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 False [0] . [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 False [0] [[[<>] [pop !-] ||] nullary] . branch [_spn_E] [_spn_T] branch
+ 23 18 . 0 [_spn_E] [_spn_T] branch
+ 23 18 0 . [_spn_E] [_spn_T] branch
+ 23 18 0 [_spn_E] . [_spn_T] branch
+ 23 18 0 [_spn_E] [_spn_T] . branch
+ 23 18 . _spn_E
+ 23 18 . [pop !-] [--] [++] ifte
+ 23 18 [pop !-] . [--] [++] ifte
+ 23 18 [pop !-] [--] . [++] ifte
+ 23 18 [pop !-] [--] [++] . ifte
+ 23 18 [pop !-] [--] [++] . [nullary not] dipd branch
+ 23 18 [pop !-] [--] [++] [nullary not] . dipd branch
+ 23 18 [pop !-] . nullary not [--] [++] branch
+ 23 18 [pop !-] . [stack] dinfrirst not [--] [++] branch
+ 23 18 [pop !-] [stack] . dinfrirst not [--] [++] branch
+ 23 18 [pop !-] [stack] . dip infra first not [--] [++] branch
+ 23 18 . stack [pop !-] infra first not [--] [++] branch
+ 23 18 [18 23] . [pop !-] infra first not [--] [++] branch
+ 23 18 [18 23] [pop !-] . infra first not [--] [++] branch
+ 23 18 . pop !- [18 23] swaack first not [--] [++] branch
+ 23 . !- [18 23] swaack first not [--] [++] branch
+ 23 . 0 >= [18 23] swaack first not [--] [++] branch
+ 23 0 . >= [18 23] swaack first not [--] [++] branch
+ True . [18 23] swaack first not [--] [++] branch
+ True [18 23] . swaack first not [--] [++] branch
+ 23 18 [True] . first not [--] [++] branch
+ 23 18 True . not [--] [++] branch
+ 23 18 False . [--] [++] branch
+ 23 18 False [--] . [++] branch
+ 23 18 False [--] [++] . branch
+ 23 18 . --
+ 23 17 .
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/Square_Spiral.ipynb b/docs/Square_Spiral.ipynb
new file mode 100644
index 0000000..8dc4273
--- /dev/null
+++ b/docs/Square_Spiral.ipynb
@@ -0,0 +1,554 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from notebook_preamble import J, V, define"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Square Spiral Example Joy Code"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "Here is the example of Joy code from the `README` file:\n",
+ "\n",
+ " [[[abs]ii <=][[<>][pop !-]||]&&][[!-][[++]][[--]]ifte dip][[pop !-][--][++]ifte]ifte\n",
+ "\n",
+ "It might seem unreadable but with a little familiarity it becomes just as\n",
+ "legible as any other notation. Some layout helps:\n",
+ "\n",
+ " [ [[abs] ii <=]\n",
+ " [\n",
+ " [<>] [pop !-] ||\n",
+ " ] &&\n",
+ " ]\n",
+ " [[ !-] [[++]] [[--]] ifte dip]\n",
+ " [[pop !-] [--] [++] ifte ]\n",
+ " ifte\n",
+ "\n",
+ "This function accepts two integers on the stack and increments or\n",
+ "decrements one of them such that the new pair of numbers is the next\n",
+ "coordinate pair in a square spiral (like the kind used to construct an\n",
+ "Ulam Spiral). \n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Original Form\n",
+ "\n",
+ "It's adapted from [the original code on StackOverflow](https://stackoverflow.com/questions/398299/looping-in-a-spiral/31864777#31864777):\n",
+ "\n",
+ "\n",
+ "> If all you're trying to do is generate the first N points in the spiral\n",
+ "> (without the original problem's constraint of masking to an N x M\n",
+ "> region), the code becomes very simple:\n",
+ "\n",
+ " void spiral(const int N)\n",
+ " {\n",
+ " int x = 0;\n",
+ " int y = 0;\n",
+ " for(int i = 0; i < N; ++i)\n",
+ " {\n",
+ " cout << x << '\\t' << y << '\\n';\n",
+ " if(abs(x) <= abs(y) && (x != y || x >= 0))\n",
+ " x += ((y >= 0) ? 1 : -1);\n",
+ " else\n",
+ " y += ((x >= 0) ? -1 : 1);\n",
+ " }\n",
+ " }"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Translation to Joy\n",
+ "\n",
+ "I'm going to make a function that take two ints (`x` and `y`) and\n",
+ "generates the next pair, we'll turn it into a generator later using the\n",
+ "`x` combinator."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### First Boolean Predicate\n",
+ "\n",
+ "We need a function that computes `abs(x) <= abs(y)`, we can use `ii` to\n",
+ "apply `abs` to both values and then compare them\n",
+ "with `<=`:\n",
+ "\n",
+ " [abs] ii <=\n",
+ "\n",
+ "I've defined two short-circuiting Boolean combinators `&&` and `||` that\n",
+ "each accept two quoted predicate programs, run the first, and\n",
+ "conditionally run the second only if required (to compute the final\n",
+ "Boolean value). They run their predicate arguments `nullary`."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "define('&& [nullary] cons [nullary [0]] dip branch')\n",
+ "define('|| [nullary] cons [nullary] dip [1] branch')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Given those, we can define `x != y || x >= 0` as:\n",
+ "\n",
+ " [<>] [pop 0 >=] ||\n",
+ "\n",
+ "And `(abs(x) <= abs(y) && (x != y || x >= 0))` as:\n",
+ "\n",
+ " [[abs] ii <=] [[<>] [pop 0 >=] ||] &&\n",
+ "\n",
+ "It's a little rough, but, as I say, with a little familiarity it becomes\n",
+ "legible."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### The Increment / Decrement Branches\n",
+ "\n",
+ "Turning to the branches of the main `if` statement:\n",
+ "\n",
+ " x += ((y >= 0) ? 1 : -1);\n",
+ "\n",
+ "Rewrite as a hybrid (pseudo-code) `ifte` expression:\n",
+ "\n",
+ " [y >= 0] [x += 1] [X -= 1] ifte\n",
+ "\n",
+ "Change each C phrase to Joy code:\n",
+ "\n",
+ " [0 >=] [[++] dip] [[--] dip] ifte\n",
+ "\n",
+ "Factor out the dip from each branch:\n",
+ "\n",
+ " [0 >=] [[++]] [[--]] ifte dip\n",
+ "\n",
+ "Similar logic applies to the other branch:\n",
+ "\n",
+ " y += ((x >= 0) ? -1 : 1);\n",
+ "\n",
+ " [x >= 0] [y -= 1] [y += 1] ifte\n",
+ "\n",
+ " [pop 0 >=] [--] [++] ifte"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### \"Not Negative\""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "define('!- 0 >=')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Putting the Pieces Together\n",
+ "\n",
+ "We can assemble the three functions we just defined in quotes and give\n",
+ "them them to the `ifte` combinator. With some arrangement to show off\n",
+ "the symmetry of the two branches, we have:\n",
+ "\n",
+ " [[[abs] ii <=] [[<>] [pop !-] ||] &&]\n",
+ " [[ !-] [[++]] [[--]] ifte dip]\n",
+ " [[pop !-] [--] [++] ifte ]\n",
+ " ifte\n",
+ "\n",
+ "As I was writing this up I realized that, since the `&&` combinator\n",
+ "doesn't consume the stack (below its quoted args), I can unquote the\n",
+ "predicate, swap the branches, and use the `branch` combinator instead of\n",
+ "`ifte`:\n",
+ "\n",
+ " [[abs] ii <=] [[<>] [pop !-] ||] &&\n",
+ " [[pop !-] [--] [++] ifte ]\n",
+ " [[ !-] [[++]] [[--]] ifte dip]\n",
+ " branch"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "define('spiral_next [[[abs] ii <=] [[<>] [pop !-] ||] &&] [[!-] [[++]] [[--]] ifte dip] [[pop !-] [--] [++] ifte] ifte')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Let's try it out:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "1 0\n"
+ ]
+ }
+ ],
+ "source": [
+ "J('0 0 spiral_next')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "1 -1\n"
+ ]
+ }
+ ],
+ "source": [
+ "J('1 0 spiral_next')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "0 -1\n"
+ ]
+ }
+ ],
+ "source": [
+ "J('1 -1 spiral_next')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "-1 -1\n"
+ ]
+ }
+ ],
+ "source": [
+ "J('0 -1 spiral_next')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Turning it into a Generator with `x`\n",
+ "\n",
+ "It can be used with the x combinator to make a kind of generator for\n",
+ "spiral square coordinates.\n",
+ "\n",
+ "\n",
+ "We can use `codireco` to make a generator\n",
+ "\n",
+ " codireco ::= cons dip rest cons\n",
+ "\n",
+ "It will look like this:\n",
+ "\n",
+ " [value [F] codireco]\n",
+ "\n",
+ "Here's a trace of how it works:\n",
+ "\n",
+ " [0 [dup ++] codireco] . x\n",
+ " [0 [dup ++] codireco] . 0 [dup ++] codireco\n",
+ " [0 [dup ++] codireco] 0 . [dup ++] codireco\n",
+ " [0 [dup ++] codireco] 0 [dup ++] . codireco\n",
+ " [0 [dup ++] codireco] 0 [dup ++] . cons dip rest cons\n",
+ " [0 [dup ++] codireco] [0 dup ++] . dip rest cons\n",
+ " . 0 dup ++ [0 [dup ++] codireco] rest cons\n",
+ " 0 . dup ++ [0 [dup ++] codireco] rest cons\n",
+ " 0 0 . ++ [0 [dup ++] codireco] rest cons\n",
+ " 0 1 . [0 [dup ++] codireco] rest cons\n",
+ " 0 1 [0 [dup ++] codireco] . rest cons\n",
+ " 0 1 [[dup ++] codireco] . cons\n",
+ " 0 [1 [dup ++] codireco] . "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "But first we have to change the `spiral_next` function to work on a\n",
+ "quoted pair of integers, and leave a copy of the pair on the stack.\n",
+ "From:\n",
+ "\n",
+ " y x spiral_next\n",
+ " ---------------------\n",
+ " y' x'\n",
+ "\n",
+ "to:\n",
+ "\n",
+ " [x y] [spiral_next] infra\n",
+ " -------------------------------\n",
+ " [x' y']"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "[0 1]\n"
+ ]
+ }
+ ],
+ "source": [
+ "J('[0 0] [spiral_next] infra')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "So our generator is:\n",
+ "\n",
+ " [[x y] [dup [spiral_next] infra] codireco]\n",
+ "\n",
+ "Or rather:\n",
+ "\n",
+ " [[0 0] [dup [spiral_next] infra] codireco]\n",
+ "\n",
+ "There is a function `make_generator` that will build the generator for us\n",
+ "out of the value and stepper function:\n",
+ "\n",
+ " [0 0] [dup [spiral_next] infra] make_generator\n",
+ " ----------------------------------------------------\n",
+ " [[0 0] [dup [spiral_next] infra] codireco]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Here it is in action:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "[0 0] [0 1] [-1 1] [-1 0]\n"
+ ]
+ }
+ ],
+ "source": [
+ "J('[0 0] [dup [spiral_next] infra] make_generator x x x x pop')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Four `x` combinators, four pairs of coordinates."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Conclusion\n",
+ "\n",
+ "So that's an example of Joy code. It's a straightforward translation of\n",
+ "the original. It's a little long for a single definition, you might\n",
+ "break it up like so:\n",
+ "\n",
+ " _spn_P ::= [[abs] ii <=] [[<>] [pop !-] ||] &&\n",
+ "\n",
+ " _spn_T ::= [ !-] [[++]] [[--]] ifte dip\n",
+ " _spn_E ::= [pop !-] [--] [++] ifte\n",
+ "\n",
+ " spiral_next ::= _spn_P [_spn_E] [_spn_T] branch\n",
+ "\n",
+ "This way it's easy to see that the function is a branch with two\n",
+ "quasi-symmetrical paths.\n",
+ "\n",
+ "We then used this function to make a simple generator of coordinate\n",
+ "pairs, where the next pair in the series can be generated at any time by\n",
+ "using the `x` combinator on the generator (which is just a quoted\n",
+ "expression containing a copy of the current pair and the \"stepper\n",
+ "function\" to generate the next pair from that.)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "define('_spn_P [[abs] ii <=] [[<>] [pop !-] ||] &&')\n",
+ "define('_spn_T [!-] [[++]] [[--]] ifte dip')\n",
+ "define('_spn_E [pop !-] [--] [++] ifte')\n",
+ "define('spiral_next _spn_P [_spn_E] [_spn_T] branch')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "metadata": {
+ "scrolled": true
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ " . 23 18 spiral_next\n",
+ " 23 . 18 spiral_next\n",
+ " 23 18 . spiral_next\n",
+ " 23 18 . _spn_P [_spn_E] [_spn_T] branch\n",
+ " 23 18 . [[abs] ii <=] [[<>] [pop !-] ||] && [_spn_E] [_spn_T] branch\n",
+ " 23 18 [[abs] ii <=] . [[<>] [pop !-] ||] && [_spn_E] [_spn_T] branch\n",
+ " 23 18 [[abs] ii <=] [[<>] [pop !-] ||] . && [_spn_E] [_spn_T] branch\n",
+ " 23 18 [[abs] ii <=] [[<>] [pop !-] ||] . [nullary] cons [nullary [0]] dip branch [_spn_E] [_spn_T] branch\n",
+ " 23 18 [[abs] ii <=] [[<>] [pop !-] ||] [nullary] . cons [nullary [0]] dip branch [_spn_E] [_spn_T] branch\n",
+ " 23 18 [[abs] ii <=] [[[<>] [pop !-] ||] nullary] . [nullary [0]] dip branch [_spn_E] [_spn_T] branch\n",
+ "23 18 [[abs] ii <=] [[[<>] [pop !-] ||] nullary] [nullary [0]] . dip branch [_spn_E] [_spn_T] branch\n",
+ " 23 18 [[abs] ii <=] . nullary [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch\n",
+ " 23 18 [[abs] ii <=] . [stack] dinfrirst [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch\n",
+ " 23 18 [[abs] ii <=] [stack] . dinfrirst [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch\n",
+ " 23 18 [[abs] ii <=] [stack] . dip infra first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch\n",
+ " 23 18 . stack [[abs] ii <=] infra first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch\n",
+ " 23 18 [18 23] . [[abs] ii <=] infra first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch\n",
+ " 23 18 [18 23] [[abs] ii <=] . infra first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch\n",
+ " 23 18 . [abs] ii <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch\n",
+ " 23 18 [abs] . ii <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch\n",
+ " 23 18 [abs] . [dip] dupdip i <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch\n",
+ " 23 18 [abs] [dip] . dupdip i <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch\n",
+ " 23 18 [abs] . dip [abs] i <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch\n",
+ " 23 . abs 18 [abs] i <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch\n",
+ " 23 . 18 [abs] i <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch\n",
+ " 23 18 . [abs] i <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch\n",
+ " 23 18 [abs] . i <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch\n",
+ " 23 18 . abs <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch\n",
+ " 23 18 . <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch\n",
+ " False . [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch\n",
+ " False [18 23] . swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch\n",
+ " 23 18 [False] . first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch\n",
+ " 23 18 False . [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch\n",
+ " 23 18 False [0] . [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch\n",
+ " 23 18 False [0] [[[<>] [pop !-] ||] nullary] . branch [_spn_E] [_spn_T] branch\n",
+ " 23 18 . 0 [_spn_E] [_spn_T] branch\n",
+ " 23 18 0 . [_spn_E] [_spn_T] branch\n",
+ " 23 18 0 [_spn_E] . [_spn_T] branch\n",
+ " 23 18 0 [_spn_E] [_spn_T] . branch\n",
+ " 23 18 . _spn_E\n",
+ " 23 18 . [pop !-] [--] [++] ifte\n",
+ " 23 18 [pop !-] . [--] [++] ifte\n",
+ " 23 18 [pop !-] [--] . [++] ifte\n",
+ " 23 18 [pop !-] [--] [++] . ifte\n",
+ " 23 18 [pop !-] [--] [++] . [nullary not] dipd branch\n",
+ " 23 18 [pop !-] [--] [++] [nullary not] . dipd branch\n",
+ " 23 18 [pop !-] . nullary not [--] [++] branch\n",
+ " 23 18 [pop !-] . [stack] dinfrirst not [--] [++] branch\n",
+ " 23 18 [pop !-] [stack] . dinfrirst not [--] [++] branch\n",
+ " 23 18 [pop !-] [stack] . dip infra first not [--] [++] branch\n",
+ " 23 18 . stack [pop !-] infra first not [--] [++] branch\n",
+ " 23 18 [18 23] . [pop !-] infra first not [--] [++] branch\n",
+ " 23 18 [18 23] [pop !-] . infra first not [--] [++] branch\n",
+ " 23 18 . pop !- [18 23] swaack first not [--] [++] branch\n",
+ " 23 . !- [18 23] swaack first not [--] [++] branch\n",
+ " 23 . 0 >= [18 23] swaack first not [--] [++] branch\n",
+ " 23 0 . >= [18 23] swaack first not [--] [++] branch\n",
+ " True . [18 23] swaack first not [--] [++] branch\n",
+ " True [18 23] . swaack first not [--] [++] branch\n",
+ " 23 18 [True] . first not [--] [++] branch\n",
+ " 23 18 True . not [--] [++] branch\n",
+ " 23 18 False . [--] [++] branch\n",
+ " 23 18 False [--] . [++] branch\n",
+ " 23 18 False [--] [++] . branch\n",
+ " 23 18 . --\n",
+ " 23 17 . \n"
+ ]
+ }
+ ],
+ "source": [
+ "V('23 18 spiral_next')"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 2",
+ "language": "python",
+ "name": "python2"
+ },
+ "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"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/docs/Square_Spiral.md b/docs/Square_Spiral.md
new file mode 100644
index 0000000..a217605
--- /dev/null
+++ b/docs/Square_Spiral.md
@@ -0,0 +1,363 @@
+```python
+from notebook_preamble import J, V, define
+```
+
+# Square Spiral Example Joy Code
+
+
+Here is the example of Joy code from the `README` file:
+
+ [[[abs]ii <=][[<>][pop !-]||]&&][[!-][[++]][[--]]ifte dip][[pop !-][--][++]ifte]ifte
+
+It might seem unreadable but with a little familiarity it becomes just as
+legible as any other notation. Some layout helps:
+
+ [ [[abs] ii <=]
+ [
+ [<>] [pop !-] ||
+ ] &&
+ ]
+ [[ !-] [[++]] [[--]] ifte dip]
+ [[pop !-] [--] [++] ifte ]
+ ifte
+
+This function accepts two integers on the stack and increments or
+decrements one of them such that the new pair of numbers is the next
+coordinate pair in a square spiral (like the kind used to construct an
+Ulam Spiral).
+
+
+
+## Original Form
+
+It's adapted from [the original code on StackOverflow](https://stackoverflow.com/questions/398299/looping-in-a-spiral/31864777#31864777):
+
+
+> If all you're trying to do is generate the first N points in the spiral
+> (without the original problem's constraint of masking to an N x M
+> region), the code becomes very simple:
+
+ void spiral(const int N)
+ {
+ int x = 0;
+ int y = 0;
+ for(int i = 0; i < N; ++i)
+ {
+ cout << x << '\t' << y << '\n';
+ if(abs(x) <= abs(y) && (x != y || x >= 0))
+ x += ((y >= 0) ? 1 : -1);
+ else
+ y += ((x >= 0) ? -1 : 1);
+ }
+ }
+
+## Translation to Joy
+
+I'm going to make a function that take two ints (`x` and `y`) and
+generates the next pair, we'll turn it into a generator later using the
+`x` combinator.
+
+### First Boolean Predicate
+
+We need a function that computes `abs(x) <= abs(y)`, we can use `ii` to
+apply `abs` to both values and then compare them
+with `<=`:
+
+ [abs] ii <=
+
+I've defined two short-circuiting Boolean combinators `&&` and `||` that
+each accept two quoted predicate programs, run the first, and
+conditionally run the second only if required (to compute the final
+Boolean value). They run their predicate arguments `nullary`.
+
+
+```python
+define('&& [nullary] cons [nullary [0]] dip branch')
+define('|| [nullary] cons [nullary] dip [1] branch')
+```
+
+Given those, we can define `x != y || x >= 0` as:
+
+ [<>] [pop 0 >=] ||
+
+And `(abs(x) <= abs(y) && (x != y || x >= 0))` as:
+
+ [[abs] ii <=] [[<>] [pop 0 >=] ||] &&
+
+It's a little rough, but, as I say, with a little familiarity it becomes
+legible.
+
+### The Increment / Decrement Branches
+
+Turning to the branches of the main `if` statement:
+
+ x += ((y >= 0) ? 1 : -1);
+
+Rewrite as a hybrid (pseudo-code) `ifte` expression:
+
+ [y >= 0] [x += 1] [X -= 1] ifte
+
+Change each C phrase to Joy code:
+
+ [0 >=] [[++] dip] [[--] dip] ifte
+
+Factor out the dip from each branch:
+
+ [0 >=] [[++]] [[--]] ifte dip
+
+Similar logic applies to the other branch:
+
+ y += ((x >= 0) ? -1 : 1);
+
+ [x >= 0] [y -= 1] [y += 1] ifte
+
+ [pop 0 >=] [--] [++] ifte
+
+### "Not Negative"
+
+
+```python
+define('!- 0 >=')
+```
+
+## Putting the Pieces Together
+
+We can assemble the three functions we just defined in quotes and give
+them them to the `ifte` combinator. With some arrangement to show off
+the symmetry of the two branches, we have:
+
+ [[[abs] ii <=] [[<>] [pop !-] ||] &&]
+ [[ !-] [[++]] [[--]] ifte dip]
+ [[pop !-] [--] [++] ifte ]
+ ifte
+
+As I was writing this up I realized that, since the `&&` combinator
+doesn't consume the stack (below its quoted args), I can unquote the
+predicate, swap the branches, and use the `branch` combinator instead of
+`ifte`:
+
+ [[abs] ii <=] [[<>] [pop !-] ||] &&
+ [[pop !-] [--] [++] ifte ]
+ [[ !-] [[++]] [[--]] ifte dip]
+ branch
+
+
+```python
+define('spiral_next [[[abs] ii <=] [[<>] [pop !-] ||] &&] [[!-] [[++]] [[--]] ifte dip] [[pop !-] [--] [++] ifte] ifte')
+```
+
+Let's try it out:
+
+
+```python
+J('0 0 spiral_next')
+```
+
+ 1 0
+
+
+
+```python
+J('1 0 spiral_next')
+```
+
+ 1 -1
+
+
+
+```python
+J('1 -1 spiral_next')
+```
+
+ 0 -1
+
+
+
+```python
+J('0 -1 spiral_next')
+```
+
+ -1 -1
+
+
+## Turning it into a Generator with `x`
+
+It can be used with the x combinator to make a kind of generator for
+spiral square coordinates.
+
+
+We can use `codireco` to make a generator
+
+ codireco ::= cons dip rest cons
+
+It will look like this:
+
+ [value [F] codireco]
+
+Here's a trace of how it works:
+
+ [0 [dup ++] codireco] . x
+ [0 [dup ++] codireco] . 0 [dup ++] codireco
+ [0 [dup ++] codireco] 0 . [dup ++] codireco
+ [0 [dup ++] codireco] 0 [dup ++] . codireco
+ [0 [dup ++] codireco] 0 [dup ++] . cons dip rest cons
+ [0 [dup ++] codireco] [0 dup ++] . dip rest cons
+ . 0 dup ++ [0 [dup ++] codireco] rest cons
+ 0 . dup ++ [0 [dup ++] codireco] rest cons
+ 0 0 . ++ [0 [dup ++] codireco] rest cons
+ 0 1 . [0 [dup ++] codireco] rest cons
+ 0 1 [0 [dup ++] codireco] . rest cons
+ 0 1 [[dup ++] codireco] . cons
+ 0 [1 [dup ++] codireco] .
+
+But first we have to change the `spiral_next` function to work on a
+quoted pair of integers, and leave a copy of the pair on the stack.
+From:
+
+ y x spiral_next
+ ---------------------
+ y' x'
+
+to:
+
+ [x y] [spiral_next] infra
+ -------------------------------
+ [x' y']
+
+
+```python
+J('[0 0] [spiral_next] infra')
+```
+
+ [0 1]
+
+
+So our generator is:
+
+ [[x y] [dup [spiral_next] infra] codireco]
+
+Or rather:
+
+ [[0 0] [dup [spiral_next] infra] codireco]
+
+There is a function `make_generator` that will build the generator for us
+out of the value and stepper function:
+
+ [0 0] [dup [spiral_next] infra] make_generator
+ ----------------------------------------------------
+ [[0 0] [dup [spiral_next] infra] codireco]
+
+Here it is in action:
+
+
+```python
+J('[0 0] [dup [spiral_next] infra] make_generator x x x x pop')
+```
+
+ [0 0] [0 1] [-1 1] [-1 0]
+
+
+Four `x` combinators, four pairs of coordinates.
+
+## Conclusion
+
+So that's an example of Joy code. It's a straightforward translation of
+the original. It's a little long for a single definition, you might
+break it up like so:
+
+ _spn_P ::= [[abs] ii <=] [[<>] [pop !-] ||] &&
+
+ _spn_T ::= [ !-] [[++]] [[--]] ifte dip
+ _spn_E ::= [pop !-] [--] [++] ifte
+
+ spiral_next ::= _spn_P [_spn_E] [_spn_T] branch
+
+This way it's easy to see that the function is a branch with two
+quasi-symmetrical paths.
+
+We then used this function to make a simple generator of coordinate
+pairs, where the next pair in the series can be generated at any time by
+using the `x` combinator on the generator (which is just a quoted
+expression containing a copy of the current pair and the "stepper
+function" to generate the next pair from that.)
+
+
+```python
+define('_spn_P [[abs] ii <=] [[<>] [pop !-] ||] &&')
+define('_spn_T [!-] [[++]] [[--]] ifte dip')
+define('_spn_E [pop !-] [--] [++] ifte')
+define('spiral_next _spn_P [_spn_E] [_spn_T] branch')
+```
+
+
+```python
+V('23 18 spiral_next')
+```
+
+ . 23 18 spiral_next
+ 23 . 18 spiral_next
+ 23 18 . spiral_next
+ 23 18 . _spn_P [_spn_E] [_spn_T] branch
+ 23 18 . [[abs] ii <=] [[<>] [pop !-] ||] && [_spn_E] [_spn_T] branch
+ 23 18 [[abs] ii <=] . [[<>] [pop !-] ||] && [_spn_E] [_spn_T] branch
+ 23 18 [[abs] ii <=] [[<>] [pop !-] ||] . && [_spn_E] [_spn_T] branch
+ 23 18 [[abs] ii <=] [[<>] [pop !-] ||] . [nullary] cons [nullary [0]] dip branch [_spn_E] [_spn_T] branch
+ 23 18 [[abs] ii <=] [[<>] [pop !-] ||] [nullary] . cons [nullary [0]] dip branch [_spn_E] [_spn_T] branch
+ 23 18 [[abs] ii <=] [[[<>] [pop !-] ||] nullary] . [nullary [0]] dip branch [_spn_E] [_spn_T] branch
+ 23 18 [[abs] ii <=] [[[<>] [pop !-] ||] nullary] [nullary [0]] . dip branch [_spn_E] [_spn_T] branch
+ 23 18 [[abs] ii <=] . nullary [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 [[abs] ii <=] . [stack] dinfrirst [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 [[abs] ii <=] [stack] . dinfrirst [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 [[abs] ii <=] [stack] . dip infra first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 . stack [[abs] ii <=] infra first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 [18 23] . [[abs] ii <=] infra first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 [18 23] [[abs] ii <=] . infra first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 . [abs] ii <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 [abs] . ii <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 [abs] . [dip] dupdip i <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 [abs] [dip] . dupdip i <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 [abs] . dip [abs] i <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 . abs 18 [abs] i <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 . 18 [abs] i <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 . [abs] i <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 [abs] . i <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 . abs <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 . <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ False . [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ False [18 23] . swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 [False] . first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 False . [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 False [0] . [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 False [0] [[[<>] [pop !-] ||] nullary] . branch [_spn_E] [_spn_T] branch
+ 23 18 . 0 [_spn_E] [_spn_T] branch
+ 23 18 0 . [_spn_E] [_spn_T] branch
+ 23 18 0 [_spn_E] . [_spn_T] branch
+ 23 18 0 [_spn_E] [_spn_T] . branch
+ 23 18 . _spn_E
+ 23 18 . [pop !-] [--] [++] ifte
+ 23 18 [pop !-] . [--] [++] ifte
+ 23 18 [pop !-] [--] . [++] ifte
+ 23 18 [pop !-] [--] [++] . ifte
+ 23 18 [pop !-] [--] [++] . [nullary not] dipd branch
+ 23 18 [pop !-] [--] [++] [nullary not] . dipd branch
+ 23 18 [pop !-] . nullary not [--] [++] branch
+ 23 18 [pop !-] . [stack] dinfrirst not [--] [++] branch
+ 23 18 [pop !-] [stack] . dinfrirst not [--] [++] branch
+ 23 18 [pop !-] [stack] . dip infra first not [--] [++] branch
+ 23 18 . stack [pop !-] infra first not [--] [++] branch
+ 23 18 [18 23] . [pop !-] infra first not [--] [++] branch
+ 23 18 [18 23] [pop !-] . infra first not [--] [++] branch
+ 23 18 . pop !- [18 23] swaack first not [--] [++] branch
+ 23 . !- [18 23] swaack first not [--] [++] branch
+ 23 . 0 >= [18 23] swaack first not [--] [++] branch
+ 23 0 . >= [18 23] swaack first not [--] [++] branch
+ True . [18 23] swaack first not [--] [++] branch
+ True [18 23] . swaack first not [--] [++] branch
+ 23 18 [True] . first not [--] [++] branch
+ 23 18 True . not [--] [++] branch
+ 23 18 False . [--] [++] branch
+ 23 18 False [--] . [++] branch
+ 23 18 False [--] [++] . branch
+ 23 18 . --
+ 23 17 .
+
diff --git a/docs/Square_Spiral.rst b/docs/Square_Spiral.rst
new file mode 100644
index 0000000..7b5e67a
--- /dev/null
+++ b/docs/Square_Spiral.rst
@@ -0,0 +1,421 @@
+.. code:: ipython3
+
+ from notebook_preamble import J, V, define
+
+Square Spiral Example Joy Code
+==============================
+
+Here is the example of Joy code from the ``README`` file:
+
+::
+
+ [[[abs]ii <=][[<>][pop !-]||]&&][[!-][[++]][[--]]ifte dip][[pop !-][--][++]ifte]ifte
+
+It might seem unreadable but with a little familiarity it becomes just
+as legible as any other notation. Some layout helps:
+
+::
+
+ [ [[abs] ii <=]
+ [
+ [<>] [pop !-] ||
+ ] &&
+ ]
+ [[ !-] [[++]] [[--]] ifte dip]
+ [[pop !-] [--] [++] ifte ]
+ ifte
+
+This function accepts two integers on the stack and increments or
+decrements one of them such that the new pair of numbers is the next
+coordinate pair in a square spiral (like the kind used to construct an
+Ulam Spiral).
+
+Original Form
+-------------
+
+It's adapted from `the original code on
+StackOverflow `__:
+
+ If all you're trying to do is generate the first N points in the
+ spiral (without the original problem's constraint of masking to an N
+ x M region), the code becomes very simple:
+
+::
+
+ void spiral(const int N)
+ {
+ int x = 0;
+ int y = 0;
+ for(int i = 0; i < N; ++i)
+ {
+ cout << x << '\t' << y << '\n';
+ if(abs(x) <= abs(y) && (x != y || x >= 0))
+ x += ((y >= 0) ? 1 : -1);
+ else
+ y += ((x >= 0) ? -1 : 1);
+ }
+ }
+
+Translation to Joy
+------------------
+
+I'm going to make a function that take two ints (``x`` and ``y``) and
+generates the next pair, we'll turn it into a generator later using the
+``x`` combinator.
+
+First Boolean Predicate
+~~~~~~~~~~~~~~~~~~~~~~~
+
+We need a function that computes ``abs(x) <= abs(y)``, we can use ``ii``
+to apply ``abs`` to both values and then compare them with ``<=``:
+
+::
+
+ [abs] ii <=
+
+I've defined two short-circuiting Boolean combinators ``&&`` and ``||``
+that each accept two quoted predicate programs, run the first, and
+conditionally run the second only if required (to compute the final
+Boolean value). They run their predicate arguments ``nullary``.
+
+.. code:: ipython3
+
+ define('&& [nullary] cons [nullary [0]] dip branch')
+ define('|| [nullary] cons [nullary] dip [1] branch')
+
+Given those, we can define ``x != y || x >= 0`` as:
+
+::
+
+ [<>] [pop 0 >=] ||
+
+And ``(abs(x) <= abs(y) && (x != y || x >= 0))`` as:
+
+::
+
+ [[abs] ii <=] [[<>] [pop 0 >=] ||] &&
+
+It's a little rough, but, as I say, with a little familiarity it becomes
+legible.
+
+The Increment / Decrement Branches
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Turning to the branches of the main ``if`` statement:
+
+::
+
+ x += ((y >= 0) ? 1 : -1);
+
+Rewrite as a hybrid (pseudo-code) ``ifte`` expression:
+
+::
+
+ [y >= 0] [x += 1] [X -= 1] ifte
+
+Change each C phrase to Joy code:
+
+::
+
+ [0 >=] [[++] dip] [[--] dip] ifte
+
+Factor out the dip from each branch:
+
+::
+
+ [0 >=] [[++]] [[--]] ifte dip
+
+Similar logic applies to the other branch:
+
+::
+
+ y += ((x >= 0) ? -1 : 1);
+
+ [x >= 0] [y -= 1] [y += 1] ifte
+
+ [pop 0 >=] [--] [++] ifte
+
+"Not Negative"
+~~~~~~~~~~~~~~
+
+.. code:: ipython3
+
+ define('!- 0 >=')
+
+Putting the Pieces Together
+---------------------------
+
+We can assemble the three functions we just defined in quotes and give
+them them to the ``ifte`` combinator. With some arrangement to show off
+the symmetry of the two branches, we have:
+
+::
+
+ [[[abs] ii <=] [[<>] [pop !-] ||] &&]
+ [[ !-] [[++]] [[--]] ifte dip]
+ [[pop !-] [--] [++] ifte ]
+ ifte
+
+As I was writing this up I realized that, since the ``&&`` combinator
+doesn't consume the stack (below its quoted args), I can unquote the
+predicate, swap the branches, and use the ``branch`` combinator instead
+of ``ifte``:
+
+::
+
+ [[abs] ii <=] [[<>] [pop !-] ||] &&
+ [[pop !-] [--] [++] ifte ]
+ [[ !-] [[++]] [[--]] ifte dip]
+ branch
+
+.. code:: ipython3
+
+ define('spiral_next [[[abs] ii <=] [[<>] [pop !-] ||] &&] [[!-] [[++]] [[--]] ifte dip] [[pop !-] [--] [++] ifte] ifte')
+
+Let's try it out:
+
+.. code:: ipython3
+
+ J('0 0 spiral_next')
+
+
+.. parsed-literal::
+
+ 1 0
+
+
+.. code:: ipython3
+
+ J('1 0 spiral_next')
+
+
+.. parsed-literal::
+
+ 1 -1
+
+
+.. code:: ipython3
+
+ J('1 -1 spiral_next')
+
+
+.. parsed-literal::
+
+ 0 -1
+
+
+.. code:: ipython3
+
+ J('0 -1 spiral_next')
+
+
+.. parsed-literal::
+
+ -1 -1
+
+
+Turning it into a Generator with ``x``
+--------------------------------------
+
+It can be used with the x combinator to make a kind of generator for
+spiral square coordinates.
+
+We can use ``codireco`` to make a generator
+
+::
+
+ codireco ::= cons dip rest cons
+
+It will look like this:
+
+::
+
+ [value [F] codireco]
+
+Here's a trace of how it works:
+
+::
+
+ [0 [dup ++] codireco] . x
+ [0 [dup ++] codireco] . 0 [dup ++] codireco
+ [0 [dup ++] codireco] 0 . [dup ++] codireco
+ [0 [dup ++] codireco] 0 [dup ++] . codireco
+ [0 [dup ++] codireco] 0 [dup ++] . cons dip rest cons
+ [0 [dup ++] codireco] [0 dup ++] . dip rest cons
+ . 0 dup ++ [0 [dup ++] codireco] rest cons
+ 0 . dup ++ [0 [dup ++] codireco] rest cons
+ 0 0 . ++ [0 [dup ++] codireco] rest cons
+ 0 1 . [0 [dup ++] codireco] rest cons
+ 0 1 [0 [dup ++] codireco] . rest cons
+ 0 1 [[dup ++] codireco] . cons
+ 0 [1 [dup ++] codireco] .
+
+But first we have to change the ``spiral_next`` function to work on a
+quoted pair of integers, and leave a copy of the pair on the stack.
+From:
+
+::
+
+ y x spiral_next
+ ---------------------
+ y' x'
+
+to:
+
+::
+
+ [x y] [spiral_next] infra
+ -------------------------------
+ [x' y']
+
+.. code:: ipython3
+
+ J('[0 0] [spiral_next] infra')
+
+
+.. parsed-literal::
+
+ [0 1]
+
+
+So our generator is:
+
+::
+
+ [[x y] [dup [spiral_next] infra] codireco]
+
+Or rather:
+
+::
+
+ [[0 0] [dup [spiral_next] infra] codireco]
+
+There is a function ``make_generator`` that will build the generator for
+us out of the value and stepper function:
+
+::
+
+ [0 0] [dup [spiral_next] infra] make_generator
+ ----------------------------------------------------
+ [[0 0] [dup [spiral_next] infra] codireco]
+
+Here it is in action:
+
+.. code:: ipython3
+
+ J('[0 0] [dup [spiral_next] infra] make_generator x x x x pop')
+
+
+.. parsed-literal::
+
+ [0 0] [0 1] [-1 1] [-1 0]
+
+
+Four ``x`` combinators, four pairs of coordinates.
+
+Conclusion
+----------
+
+So that's an example of Joy code. It's a straightforward translation of
+the original. It's a little long for a single definition, you might
+break it up like so:
+
+::
+
+ _spn_P ::= [[abs] ii <=] [[<>] [pop !-] ||] &&
+
+ _spn_T ::= [ !-] [[++]] [[--]] ifte dip
+ _spn_E ::= [pop !-] [--] [++] ifte
+
+ spiral_next ::= _spn_P [_spn_E] [_spn_T] branch
+
+This way it's easy to see that the function is a branch with two
+quasi-symmetrical paths.
+
+We then used this function to make a simple generator of coordinate
+pairs, where the next pair in the series can be generated at any time by
+using the ``x`` combinator on the generator (which is just a quoted
+expression containing a copy of the current pair and the "stepper
+function" to generate the next pair from that.)
+
+.. code:: ipython3
+
+ define('_spn_P [[abs] ii <=] [[<>] [pop !-] ||] &&')
+ define('_spn_T [!-] [[++]] [[--]] ifte dip')
+ define('_spn_E [pop !-] [--] [++] ifte')
+ define('spiral_next _spn_P [_spn_E] [_spn_T] branch')
+
+.. code:: ipython3
+
+ V('23 18 spiral_next')
+
+
+.. parsed-literal::
+
+ . 23 18 spiral_next
+ 23 . 18 spiral_next
+ 23 18 . spiral_next
+ 23 18 . _spn_P [_spn_E] [_spn_T] branch
+ 23 18 . [[abs] ii <=] [[<>] [pop !-] ||] && [_spn_E] [_spn_T] branch
+ 23 18 [[abs] ii <=] . [[<>] [pop !-] ||] && [_spn_E] [_spn_T] branch
+ 23 18 [[abs] ii <=] [[<>] [pop !-] ||] . && [_spn_E] [_spn_T] branch
+ 23 18 [[abs] ii <=] [[<>] [pop !-] ||] . [nullary] cons [nullary [0]] dip branch [_spn_E] [_spn_T] branch
+ 23 18 [[abs] ii <=] [[<>] [pop !-] ||] [nullary] . cons [nullary [0]] dip branch [_spn_E] [_spn_T] branch
+ 23 18 [[abs] ii <=] [[[<>] [pop !-] ||] nullary] . [nullary [0]] dip branch [_spn_E] [_spn_T] branch
+ 23 18 [[abs] ii <=] [[[<>] [pop !-] ||] nullary] [nullary [0]] . dip branch [_spn_E] [_spn_T] branch
+ 23 18 [[abs] ii <=] . nullary [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 [[abs] ii <=] . [stack] dinfrirst [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 [[abs] ii <=] [stack] . dinfrirst [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 [[abs] ii <=] [stack] . dip infra first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 . stack [[abs] ii <=] infra first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 [18 23] . [[abs] ii <=] infra first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 [18 23] [[abs] ii <=] . infra first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 . [abs] ii <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 [abs] . ii <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 [abs] . [dip] dupdip i <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 [abs] [dip] . dupdip i <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 [abs] . dip [abs] i <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 . abs 18 [abs] i <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 . 18 [abs] i <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 . [abs] i <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 [abs] . i <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 . abs <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 . <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ False . [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ False [18 23] . swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 [False] . first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 False . [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 False [0] . [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 False [0] [[[<>] [pop !-] ||] nullary] . branch [_spn_E] [_spn_T] branch
+ 23 18 . 0 [_spn_E] [_spn_T] branch
+ 23 18 0 . [_spn_E] [_spn_T] branch
+ 23 18 0 [_spn_E] . [_spn_T] branch
+ 23 18 0 [_spn_E] [_spn_T] . branch
+ 23 18 . _spn_E
+ 23 18 . [pop !-] [--] [++] ifte
+ 23 18 [pop !-] . [--] [++] ifte
+ 23 18 [pop !-] [--] . [++] ifte
+ 23 18 [pop !-] [--] [++] . ifte
+ 23 18 [pop !-] [--] [++] . [nullary not] dipd branch
+ 23 18 [pop !-] [--] [++] [nullary not] . dipd branch
+ 23 18 [pop !-] . nullary not [--] [++] branch
+ 23 18 [pop !-] . [stack] dinfrirst not [--] [++] branch
+ 23 18 [pop !-] [stack] . dinfrirst not [--] [++] branch
+ 23 18 [pop !-] [stack] . dip infra first not [--] [++] branch
+ 23 18 . stack [pop !-] infra first not [--] [++] branch
+ 23 18 [18 23] . [pop !-] infra first not [--] [++] branch
+ 23 18 [18 23] [pop !-] . infra first not [--] [++] branch
+ 23 18 . pop !- [18 23] swaack first not [--] [++] branch
+ 23 . !- [18 23] swaack first not [--] [++] branch
+ 23 . 0 >= [18 23] swaack first not [--] [++] branch
+ 23 0 . >= [18 23] swaack first not [--] [++] branch
+ True . [18 23] swaack first not [--] [++] branch
+ True [18 23] . swaack first not [--] [++] branch
+ 23 18 [True] . first not [--] [++] branch
+ 23 18 True . not [--] [++] branch
+ 23 18 False . [--] [++] branch
+ 23 18 False [--] . [++] branch
+ 23 18 False [--] [++] . branch
+ 23 18 . --
+ 23 17 .
+
diff --git a/docs/sphinx_docs/_build/doctrees/environment.pickle b/docs/sphinx_docs/_build/doctrees/environment.pickle
index c2efa5d..1710eb5 100644
Binary files a/docs/sphinx_docs/_build/doctrees/environment.pickle and b/docs/sphinx_docs/_build/doctrees/environment.pickle differ
diff --git a/docs/sphinx_docs/_build/doctrees/index.doctree b/docs/sphinx_docs/_build/doctrees/index.doctree
index 35d5feb..2f8a002 100644
Binary files a/docs/sphinx_docs/_build/doctrees/index.doctree and b/docs/sphinx_docs/_build/doctrees/index.doctree differ
diff --git a/docs/sphinx_docs/_build/doctrees/notebooks/Derivatives_of_Regular_Expressions.doctree b/docs/sphinx_docs/_build/doctrees/notebooks/Derivatives_of_Regular_Expressions.doctree
index f834481..c5f9725 100644
Binary files a/docs/sphinx_docs/_build/doctrees/notebooks/Derivatives_of_Regular_Expressions.doctree and b/docs/sphinx_docs/_build/doctrees/notebooks/Derivatives_of_Regular_Expressions.doctree differ
diff --git a/docs/sphinx_docs/_build/doctrees/notebooks/Generator_Programs.doctree b/docs/sphinx_docs/_build/doctrees/notebooks/Generator_Programs.doctree
index eac2cc4..ccb3948 100644
Binary files a/docs/sphinx_docs/_build/doctrees/notebooks/Generator_Programs.doctree and b/docs/sphinx_docs/_build/doctrees/notebooks/Generator_Programs.doctree differ
diff --git a/docs/sphinx_docs/_build/doctrees/notebooks/Newton-Raphson.doctree b/docs/sphinx_docs/_build/doctrees/notebooks/Newton-Raphson.doctree
index 1367d10..4a86f59 100644
Binary files a/docs/sphinx_docs/_build/doctrees/notebooks/Newton-Raphson.doctree and b/docs/sphinx_docs/_build/doctrees/notebooks/Newton-Raphson.doctree differ
diff --git a/docs/sphinx_docs/_build/doctrees/notebooks/Ordered_Binary_Trees.doctree b/docs/sphinx_docs/_build/doctrees/notebooks/Ordered_Binary_Trees.doctree
index 38d5c96..67405fe 100644
Binary files a/docs/sphinx_docs/_build/doctrees/notebooks/Ordered_Binary_Trees.doctree and b/docs/sphinx_docs/_build/doctrees/notebooks/Ordered_Binary_Trees.doctree differ
diff --git a/docs/sphinx_docs/_build/doctrees/notebooks/Quadratic.doctree b/docs/sphinx_docs/_build/doctrees/notebooks/Quadratic.doctree
index 11a77fc..9506af3 100644
Binary files a/docs/sphinx_docs/_build/doctrees/notebooks/Quadratic.doctree and b/docs/sphinx_docs/_build/doctrees/notebooks/Quadratic.doctree differ
diff --git a/docs/sphinx_docs/_build/doctrees/notebooks/Recursion_Combinators.doctree b/docs/sphinx_docs/_build/doctrees/notebooks/Recursion_Combinators.doctree
index 32d4dc1..fd0934b 100644
Binary files a/docs/sphinx_docs/_build/doctrees/notebooks/Recursion_Combinators.doctree and b/docs/sphinx_docs/_build/doctrees/notebooks/Recursion_Combinators.doctree differ
diff --git a/docs/sphinx_docs/_build/doctrees/notebooks/Replacing.doctree b/docs/sphinx_docs/_build/doctrees/notebooks/Replacing.doctree
index 3bde7b5..2ad1055 100644
Binary files a/docs/sphinx_docs/_build/doctrees/notebooks/Replacing.doctree and b/docs/sphinx_docs/_build/doctrees/notebooks/Replacing.doctree differ
diff --git a/docs/sphinx_docs/_build/doctrees/notebooks/Square_Spiral.doctree b/docs/sphinx_docs/_build/doctrees/notebooks/Square_Spiral.doctree
new file mode 100644
index 0000000..e80264a
Binary files /dev/null and b/docs/sphinx_docs/_build/doctrees/notebooks/Square_Spiral.doctree differ
diff --git a/docs/sphinx_docs/_build/doctrees/notebooks/Treestep.doctree b/docs/sphinx_docs/_build/doctrees/notebooks/Treestep.doctree
index 62d36b7..91f5241 100644
Binary files a/docs/sphinx_docs/_build/doctrees/notebooks/Treestep.doctree and b/docs/sphinx_docs/_build/doctrees/notebooks/Treestep.doctree differ
diff --git a/docs/sphinx_docs/_build/doctrees/notebooks/TypeChecking.doctree b/docs/sphinx_docs/_build/doctrees/notebooks/TypeChecking.doctree
index 646bf47..ad9a5c1 100644
Binary files a/docs/sphinx_docs/_build/doctrees/notebooks/TypeChecking.doctree and b/docs/sphinx_docs/_build/doctrees/notebooks/TypeChecking.doctree differ
diff --git a/docs/sphinx_docs/_build/doctrees/notebooks/Types.doctree b/docs/sphinx_docs/_build/doctrees/notebooks/Types.doctree
index e144f9e..9ba07c8 100644
Binary files a/docs/sphinx_docs/_build/doctrees/notebooks/Types.doctree and b/docs/sphinx_docs/_build/doctrees/notebooks/Types.doctree differ
diff --git a/docs/sphinx_docs/_build/doctrees/notebooks/Zipper.doctree b/docs/sphinx_docs/_build/doctrees/notebooks/Zipper.doctree
index e51d16c..22f043b 100644
Binary files a/docs/sphinx_docs/_build/doctrees/notebooks/Zipper.doctree and b/docs/sphinx_docs/_build/doctrees/notebooks/Zipper.doctree differ
diff --git a/docs/sphinx_docs/_build/doctrees/notebooks/index.doctree b/docs/sphinx_docs/_build/doctrees/notebooks/index.doctree
index d8c2f71..4eb8e5f 100644
Binary files a/docs/sphinx_docs/_build/doctrees/notebooks/index.doctree and b/docs/sphinx_docs/_build/doctrees/notebooks/index.doctree differ
diff --git a/docs/sphinx_docs/_build/html/_sources/index.rst.txt b/docs/sphinx_docs/_build/html/_sources/index.rst.txt
index b29fc83..eddc007 100644
--- a/docs/sphinx_docs/_build/html/_sources/index.rst.txt
+++ b/docs/sphinx_docs/_build/html/_sources/index.rst.txt
@@ -34,6 +34,31 @@ itself.
.. _Concatinative: https://en.wikipedia.org/wiki/Concatenative_programming_language
+Example Code
+--------------------------------------------------
+
+Here is an example of Joy code::
+
+ [[[abs]ii <=][[<>][pop !-]||]&&][[!-][[++]][[--]]ifte dip][[pop !-][--][++]ifte]ifte
+
+It might seem unreadable but with a little familiarity it becomes just as
+legible as any other notation. Some layout helps::
+
+ [ [[abs] ii <=]
+ [
+ [<>] [pop !-] ||
+ ] &&
+ ]
+ [[ !-] [[++]] [[--]] ifte dip]
+ [[pop !-] [--] [++] ifte ]
+ ifte
+
+This function accepts two integers on the stack and increments or
+decrements one of them such that the new pair of numbers is the next
+coordinate pair in a square spiral (like the kind used to construct an
+Ulam Spiral). For more information see :doc:`notebooks/Square_Spiral`
+
+
Quick Start
--------------------------------------------------
diff --git a/docs/sphinx_docs/_build/html/_sources/notebooks/Derivatives_of_Regular_Expressions.rst.txt b/docs/sphinx_docs/_build/html/_sources/notebooks/Derivatives_of_Regular_Expressions.rst.txt
index be09155..29dc9fb 100644
--- a/docs/sphinx_docs/_build/html/_sources/notebooks/Derivatives_of_Regular_Expressions.rst.txt
+++ b/docs/sphinx_docs/_build/html/_sources/notebooks/Derivatives_of_Regular_Expressions.rst.txt
@@ -76,7 +76,7 @@ E.g.:
Implementation
--------------
-.. code:: python
+.. code:: ipython2
from functools import partial as curry
from itertools import product
@@ -86,7 +86,7 @@ Implementation
The empty set and the set of just the empty string.
-.. code:: python
+.. code:: ipython2
phi = frozenset() # Ï
y = frozenset({''}) # λ
@@ -101,7 +101,7 @@ alphabet with two symbols (if you had to.)
I chose the names ``O`` and ``l`` (uppercase âoâ and lowercase âLâ) to
look like ``0`` and ``1`` (zero and one) respectively.
-.. code:: python
+.. code:: ipython2
syms = O, l = frozenset({'0'}), frozenset({'1'})
@@ -123,7 +123,7 @@ expression* is one of:
Where ``R`` and ``S`` stand for *regular expressions*.
-.. code:: python
+.. code:: ipython2
AND, CONS, KSTAR, NOT, OR = 'and cons * not or'.split() # Tags are just strings.
@@ -133,7 +133,7 @@ only, these datastructures are immutable.
String Representation of RE Datastructures
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.. code:: python
+.. code:: ipython2
def stringy(re):
'''
@@ -175,11 +175,11 @@ Match anything. Often spelled â.â
I = (0|1)*
-.. code:: python
+.. code:: ipython2
I = (KSTAR, (OR, O, l))
-.. code:: python
+.. code:: ipython2
print stringy(I)
@@ -201,14 +201,14 @@ The example expression from Brzozowski:
Note that it contains one of everything.
-.. code:: python
+.. code:: ipython2
a = (CONS, I, (CONS, l, (CONS, l, (CONS, l, I))))
b = (CONS, I, (CONS, O, l))
c = (CONS, l, (KSTAR, l))
it = (AND, a, (NOT, (OR, b, c)))
-.. code:: python
+.. code:: ipython2
print stringy(it)
@@ -223,7 +223,7 @@ Note that it contains one of everything.
Letâs get that auxiliary predicate function ``δ`` out of the way.
-.. code:: python
+.. code:: ipython2
def nully(R):
'''
@@ -263,7 +263,7 @@ This is the straightforward version with no âcompactionâ. It works fine,
but does waaaay too much work because the expressions grow each
derivation.
-.. code:: python
+.. code:: ipython2
def D(symbol):
@@ -308,7 +308,7 @@ derivation.
Compaction Rules
~~~~~~~~~~~~~~~~
-.. code:: python
+.. code:: ipython2
def _compaction_rule(relation, one, zero, a, b):
return (
@@ -320,7 +320,7 @@ Compaction Rules
An elegant symmetry.
-.. code:: python
+.. code:: ipython2
# R ⧠I = I ⧠R = R
# R â§ Ï = Ï â§ R = Ï
@@ -341,7 +341,7 @@ We can save re-processing by remembering results we have already
computed. RE datastructures are immutable and the ``derv()`` functions
are *pure* so this is fine.
-.. code:: python
+.. code:: ipython2
class Memo(object):
@@ -365,7 +365,7 @@ With âCompactionâ
This version uses the rules above to perform compaction. It keeps the
expressions from growing too large.
-.. code:: python
+.. code:: ipython2
def D_compaction(symbol):
@@ -414,7 +414,7 @@ Letâs try it outâ¦
(FIXME: redo.)
-.. code:: python
+.. code:: ipython2
o, z = D_compaction('0'), D_compaction('1')
REs = set()
@@ -533,10 +533,10 @@ machine transition table.
Says, âThree or more 1âs and not ending in 01 nor composed of all 1âs.â
-.. figure:: omg.svg
- :alt: State Machine Graph
+.. figure:: attachment:omg.svg
+ :alt: omg.svg
- State Machine Graph
+ omg.svg
Start at ``a`` and follow the transition arrows according to their
labels. Accepting states have a double outline. (Graphic generated with
@@ -605,20 +605,20 @@ You can see the one-way nature of the ``g`` state and the ``hij`` âtrapâ
in the way that the ``.111.`` on the left-hand side of the ``&``
disappears once it has been matched.
-.. code:: python
+.. code:: ipython2
from collections import defaultdict
from pprint import pprint
from string import ascii_lowercase
-.. code:: python
+.. code:: ipython2
d0, d1 = D_compaction('0'), D_compaction('1')
``explore()``
~~~~~~~~~~~~~
-.. code:: python
+.. code:: ipython2
def explore(re):
@@ -645,7 +645,7 @@ disappears once it has been matched.
return table, accepting
-.. code:: python
+.. code:: ipython2
table, accepting = explore(it)
table
@@ -678,7 +678,7 @@ disappears once it has been matched.
-.. code:: python
+.. code:: ipython2
accepting
@@ -697,7 +697,7 @@ Generate Diagram
Once we have the FSM table and the set of accepting states we can
generate the diagram above.
-.. code:: python
+.. code:: ipython2
_template = '''\
digraph finite_state_machine {
@@ -722,7 +722,7 @@ generate the diagram above.
)
)
-.. code:: python
+.. code:: ipython2
print make_graph(table, accepting)
@@ -776,7 +776,7 @@ Trampoline Function
Python has no GOTO statement but we can fake it with a âtrampolineâ
function.
-.. code:: python
+.. code:: ipython2
def trampoline(input_, jump_from, accepting):
I = iter(input_)
@@ -793,7 +793,7 @@ Stream Functions
Little helpers to process the iterator of our data (a âstreamâ of â1â
and â0â characters, not bits.)
-.. code:: python
+.. code:: ipython2
getch = lambda I: int(next(I))
@@ -816,7 +816,7 @@ code. (You have to imagine that these are GOTO statements in C or
branches in assembly and that the state names are branch destination
labels.)
-.. code:: python
+.. code:: ipython2
a = lambda I: c if getch(I) else b
b = lambda I: _0(I) or d
@@ -833,12 +833,12 @@ Note that the implementations of ``h`` and ``g`` are identical ergo
``h = g`` and we could eliminate one in the code but ``h`` is an
accepting state and ``g`` isnât.
-.. code:: python
+.. code:: ipython2
def acceptable(input_):
return trampoline(input_, a, {h, i})
-.. code:: python
+.. code:: ipython2
for n in range(2**5):
s = bin(n)[2:]
diff --git a/docs/sphinx_docs/_build/html/_sources/notebooks/Generator_Programs.rst.txt b/docs/sphinx_docs/_build/html/_sources/notebooks/Generator_Programs.rst.txt
index a59df18..55e1679 100644
--- a/docs/sphinx_docs/_build/html/_sources/notebooks/Generator_Programs.rst.txt
+++ b/docs/sphinx_docs/_build/html/_sources/notebooks/Generator_Programs.rst.txt
@@ -3,7 +3,7 @@ Using ``x`` to Generate Values
Cf. jp-reprod.html
-.. code:: python
+.. code:: ipython2
from notebook_preamble import J, V, define
@@ -57,7 +57,7 @@ We can make a generator for the Natural numbers (0, 1, 2, â¦) by using
Letâs try it:
-.. code:: python
+.. code:: ipython2
V('[0 swap [dup ++] dip rest cons] x')
@@ -81,7 +81,7 @@ Letâs try it:
After one application of ``x`` the quoted program contains ``1`` and
``0`` is below it on the stack.
-.. code:: python
+.. code:: ipython2
J('[0 swap [dup ++] dip rest cons] x x x x x pop')
@@ -94,11 +94,11 @@ After one application of ``x`` the quoted program contains ``1`` and
``direco``
----------
-.. code:: python
+.. code:: ipython2
define('direco == dip rest cons')
-.. code:: python
+.. code:: ipython2
V('[0 swap [dup ++] direco] x')
@@ -149,13 +149,13 @@ Reading from the bottom up:
G == [direco] cons [swap] swap concat cons
G == [direco] cons [swap] swoncat cons
-.. code:: python
+.. code:: ipython2
define('G == [direco] cons [swap] swoncat cons')
Letâs try it out:
-.. code:: python
+.. code:: ipython2
J('0 [dup ++] G')
@@ -165,7 +165,7 @@ Letâs try it out:
[0 swap [dup ++] direco]
-.. code:: python
+.. code:: ipython2
J('0 [dup ++] G x x x pop')
@@ -178,7 +178,7 @@ Letâs try it out:
Powers of 2
~~~~~~~~~~~
-.. code:: python
+.. code:: ipython2
J('1 [dup 1 <<] G x x x x x x x x x pop')
@@ -194,7 +194,7 @@ Powers of 2
If we have one of these quoted programs we can drive it using ``times``
with the ``x`` combinator.
-.. code:: python
+.. code:: ipython2
J('23 [dup ++] G 5 [x] times')
@@ -226,11 +226,11 @@ int:
And pick them off by masking with 3 (binary 11) and then shifting the
int right two bits.
-.. code:: python
+.. code:: ipython2
define('PE1.1 == dup [3 &] dip 2 >>')
-.. code:: python
+.. code:: ipython2
V('14811 PE1.1')
@@ -252,7 +252,7 @@ int right two bits.
If we plug ``14811`` and ``[PE1.1]`` into our generator formâ¦
-.. code:: python
+.. code:: ipython2
J('14811 [PE1.1] G')
@@ -264,7 +264,7 @@ If we plug ``14811`` and ``[PE1.1]`` into our generator formâ¦
â¦we get a generator that works for seven cycles before it reaches zero:
-.. code:: python
+.. code:: ipython2
J('[14811 swap [PE1.1] direco] 7 [x] times')
@@ -280,11 +280,11 @@ Reset at Zero
We need a function that checks if the int has reached zero and resets it
if so.
-.. code:: python
+.. code:: ipython2
define('PE1.1.check == dup [pop 14811] [] branch')
-.. code:: python
+.. code:: ipython2
J('14811 [PE1.1.check PE1.1] G')
@@ -294,7 +294,7 @@ if so.
[14811 swap [PE1.1.check PE1.1] direco]
-.. code:: python
+.. code:: ipython2
J('[14811 swap [PE1.1.check PE1.1] direco] 21 [x] times')
@@ -316,7 +316,7 @@ In the PE1 problem we are asked to sum all the multiples of three and
five less than 1000. Itâs worked out that we need to use all seven
numbers sixty-six times and then four more.
-.. code:: python
+.. code:: ipython2
J('7 66 * 4 +')
@@ -328,7 +328,7 @@ numbers sixty-six times and then four more.
If we drive our generator 466 times and sum the stack we get 999.
-.. code:: python
+.. code:: ipython2
J('[14811 swap [PE1.1.check PE1.1] direco] 466 [x] times')
@@ -338,7 +338,7 @@ If we drive our generator 466 times and sum the stack we get 999.
3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 [57 swap [PE1.1.check PE1.1] direco]
-.. code:: python
+.. code:: ipython2
J('[14811 swap [PE1.1.check PE1.1] direco] 466 [x] times pop enstacken sum')
@@ -351,13 +351,13 @@ If we drive our generator 466 times and sum the stack we get 999.
Project Euler Problem One
-------------------------
-.. code:: python
+.. code:: ipython2
define('PE1.2 == + dup [+] dip')
Now we can add ``PE1.2`` to the quoted program given to ``G``.
-.. code:: python
+.. code:: ipython2
J('0 0 0 [PE1.1.check PE1.1] G 466 [x [PE1.2] dip] times popop')
@@ -445,15 +445,15 @@ Putting it all together:
F == + [popdd over] cons infra uncons
fib_gen == [1 1 F]
-.. code:: python
+.. code:: ipython2
define('fib == + [popdd over] cons infra uncons')
-.. code:: python
+.. code:: ipython2
define('fib_gen == [1 1 fib]')
-.. code:: python
+.. code:: ipython2
J('fib_gen 10 [x] times')
@@ -473,14 +473,14 @@ Now that we have a generator for the Fibonacci sequence, we need a
function that adds a term in the sequence to a sum if it is even, and
``pop``\ s it otherwise.
-.. code:: python
+.. code:: ipython2
define('PE2.1 == dup 2 % [+] [pop] branch')
And a predicate function that detects when the terms in the series
âexceed four millionâ.
-.. code:: python
+.. code:: ipython2
define('>4M == 4000000 >')
@@ -488,11 +488,11 @@ Now itâs straightforward to define ``PE2`` as a recursive function that
generates terms in the Fibonacci sequence until they exceed four million
and sums the even ones.
-.. code:: python
+.. code:: ipython2
define('PE2 == 0 fib_gen x [pop >4M] [popop] [[PE2.1] dip x] primrec')
-.. code:: python
+.. code:: ipython2
J('PE2')
@@ -535,7 +535,7 @@ So the Fibonacci sequence considered in terms of just parity would be:
Every third term is even.
-.. code:: python
+.. code:: ipython2
J('[1 0 fib] x x x') # To start the sequence with 1 1 2 3 instead of 1 2 3.
@@ -547,7 +547,7 @@ Every third term is even.
Drive the generator three times and ``popop`` the two odd terms.
-.. code:: python
+.. code:: ipython2
J('[1 0 fib] x x x [popop] dipd')
@@ -557,11 +557,11 @@ Drive the generator three times and ``popop`` the two odd terms.
2 [3 2 fib]
-.. code:: python
+.. code:: ipython2
define('PE2.2 == x x x [popop] dipd')
-.. code:: python
+.. code:: ipython2
J('[1 0 fib] 10 [PE2.2] times')
@@ -574,7 +574,7 @@ Drive the generator three times and ``popop`` the two odd terms.
Replace ``x`` with our new driver function ``PE2.2`` and start our
``fib`` generator at ``1 0``.
-.. code:: python
+.. code:: ipython2
J('0 [1 0 fib] PE2.2 [pop >4M] [popop] [[PE2.1] dip PE2.2] primrec')
@@ -593,11 +593,11 @@ modifications to the default ``x``?
An Interesting Variation
------------------------
-.. code:: python
+.. code:: ipython2
define('codireco == cons dip rest cons')
-.. code:: python
+.. code:: ipython2
V('[0 [dup ++] codireco] x')
@@ -620,11 +620,11 @@ An Interesting Variation
0 [1 [dup ++] codireco] .
-.. code:: python
+.. code:: ipython2
define('G == [codireco] cons cons')
-.. code:: python
+.. code:: ipython2
J('230 [dup ++] G 5 [x] times pop')
diff --git a/docs/sphinx_docs/_build/html/_sources/notebooks/Newton-Raphson.rst.txt b/docs/sphinx_docs/_build/html/_sources/notebooks/Newton-Raphson.rst.txt
index b580502..cb3f759 100644
--- a/docs/sphinx_docs/_build/html/_sources/notebooks/Newton-Raphson.rst.txt
+++ b/docs/sphinx_docs/_build/html/_sources/notebooks/Newton-Raphson.rst.txt
@@ -7,7 +7,7 @@ to write a function that can compute the square root of a number.
Cf. `"Why Functional Programming Matters" by John
Hughes `__
-.. code:: python
+.. code:: ipython3
from notebook_preamble import J, V, define
@@ -75,11 +75,11 @@ The generator can be written as:
1 [23 over / + 2 /] [dup] swoncat make_generator
1 [dup 23 over / + 2 /] make_generator
-.. code:: python
+.. code:: ipython3
define('gsra 1 swap [over / + 2 /] cons [dup] swoncat make_generator')
-.. code:: python
+.. code:: ipython3
J('23 gsra')
@@ -92,7 +92,7 @@ The generator can be written as:
Let's drive the generator a few time (with the ``x`` combinator) and
square the approximation to see how well it works...
-.. code:: python
+.. code:: ipython3
J('23 gsra 6 [x popd] times first sqr')
@@ -142,7 +142,7 @@ Predicate
abs(a-b) ε <=
(abs(a-b)<=ε)
-.. code:: python
+.. code:: ipython3
define('_within_P [first - abs] dip <=')
@@ -156,7 +156,7 @@ Base-Case
[b G] first
b
-.. code:: python
+.. code:: ipython3
define('_within_B roll< popop first')
@@ -184,7 +184,7 @@ Pretty straightforward:
b [c G] ε within
-.. code:: python
+.. code:: ipython3
define('_within_R [popd x] dip')
@@ -199,14 +199,14 @@ The recursive function we have defined so far needs a slight preamble:
[a G] x ε ...
a [b G] ε ...
-.. code:: python
+.. code:: ipython3
define('within x 0.000000001 [_within_P] [_within_B] [_within_R] tailrec')
define('sqrt gsra within')
Try it out...
-.. code:: python
+.. code:: ipython3
J('36 sqrt')
@@ -216,7 +216,7 @@ Try it out...
6.0
-.. code:: python
+.. code:: ipython3
J('23 sqrt')
@@ -228,7 +228,7 @@ Try it out...
Check it.
-.. code:: python
+.. code:: ipython3
4.795831523312719**2
@@ -241,7 +241,7 @@ Check it.
-.. code:: python
+.. code:: ipython3
from math import sqrt
diff --git a/docs/sphinx_docs/_build/html/_sources/notebooks/Ordered_Binary_Trees.rst.txt b/docs/sphinx_docs/_build/html/_sources/notebooks/Ordered_Binary_Trees.rst.txt
index a625ac3..569d665 100644
--- a/docs/sphinx_docs/_build/html/_sources/notebooks/Ordered_Binary_Trees.rst.txt
+++ b/docs/sphinx_docs/_build/html/_sources/notebooks/Ordered_Binary_Trees.rst.txt
@@ -36,7 +36,7 @@ implementation under the hood. (Where does the âtypeâ come from? It has
a contingent existence predicated on the disciplined use of these
functions on otherwise undistinguished Joy datastructures.)
-.. code:: python
+.. code:: ipython2
from notebook_preamble import D, J, V, define, DefinitionWrapper
@@ -87,11 +87,11 @@ Definition:
Tree-new == swap [[] []] cons cons
-.. code:: python
+.. code:: ipython2
define('Tree-new == swap [[] []] cons cons')
-.. code:: python
+.. code:: ipython2
J('"v" "k" Tree-new')
@@ -163,11 +163,11 @@ comparison operator:
P < == pop roll> pop first <
P == pop roll> pop first
-.. code:: python
+.. code:: ipython2
define('P == pop roll> pop first')
-.. code:: python
+.. code:: ipython2
J('["old_key" 23 [] []] 17 "new_key" ["..."] P')
@@ -242,11 +242,11 @@ And so ``T`` is just:
T == cons cons [dipdd] cons infra
-.. code:: python
+.. code:: ipython2
define('T == cons cons [dipdd] cons infra')
-.. code:: python
+.. code:: ipython2
J('["old_k" "old_value" "left" "right"] "new_value" "new_key" ["Tree-add"] T')
@@ -266,7 +266,7 @@ This is very very similar to the above:
[key_n value_n left right] value key [Tree-add] E
[key_n value_n left right] value key [Tree-add] [P <] [Te] [Ee] ifte
-.. code:: python
+.. code:: ipython2
define('E == [P <] [Te] [Ee] ifte')
@@ -278,11 +278,11 @@ instead of the right, so the only difference is that it must use
Te == cons cons [dipd] cons infra
-.. code:: python
+.. code:: ipython2
define('Te == cons cons [dipd] cons infra')
-.. code:: python
+.. code:: ipython2
J('["old_k" "old_value" "left" "right"] "new_value" "new_key" ["Tree-add"] Te')
@@ -320,11 +320,11 @@ Example:
key new_value [ left right] cons cons
[key new_value left right]
-.. code:: python
+.. code:: ipython2
define('Ee == pop swap roll< rest rest cons cons')
-.. code:: python
+.. code:: ipython2
J('["k" "old_value" "left" "right"] "new_value" "k" ["Tree-add"] Ee')
@@ -355,14 +355,14 @@ Putting it all together:
Tree-add == [popop not] [[pop] dipd Tree-new] [] [R] genrec
-.. code:: python
+.. code:: ipython2
define('Tree-add == [popop not] [[pop] dipd Tree-new] [] [[P >] [T] [E] ifte] genrec')
Examples
~~~~~~~~
-.. code:: python
+.. code:: ipython2
J('[] 23 "b" Tree-add') # Initial
@@ -372,7 +372,7 @@ Examples
['b' 23 [] []]
-.. code:: python
+.. code:: ipython2
J('["b" 23 [] []] 88 "c" Tree-add') # Greater than
@@ -382,7 +382,7 @@ Examples
['b' 23 [] ['c' 88 [] []]]
-.. code:: python
+.. code:: ipython2
J('["b" 23 [] []] 88 "a" Tree-add') # Less than
@@ -392,7 +392,7 @@ Examples
['b' 23 ['a' 88 [] []] []]
-.. code:: python
+.. code:: ipython2
J('["b" 23 [] []] 88 "b" Tree-add') # Equal to
@@ -402,7 +402,7 @@ Examples
['b' 88 [] []]
-.. code:: python
+.. code:: ipython2
J('[] 23 "b" Tree-add 88 "a" Tree-add 44 "c" Tree-add') # Series.
@@ -412,7 +412,7 @@ Examples
['b' 23 ['a' 88 [] []] ['c' 44 [] []]]
-.. code:: python
+.. code:: ipython2
J('[] [[23 "b"] [88 "a"] [44 "c"]] [i Tree-add] step')
@@ -444,7 +444,7 @@ values:
------------------------- a < b
L
-.. code:: python
+.. code:: ipython2
J("1 0 ['G'] ['E'] ['L'] cmp")
@@ -454,7 +454,7 @@ values:
'G'
-.. code:: python
+.. code:: ipython2
J("1 1 ['G'] ['E'] ['L'] cmp")
@@ -464,7 +464,7 @@ values:
'E'
-.. code:: python
+.. code:: ipython2
J("0 1 ['G'] ['E'] ['L'] cmp")
@@ -514,7 +514,7 @@ Or just:
P == over [popop popop first] nullary
-.. code:: python
+.. code:: ipython2
define('P == over [popop popop first] nullary')
@@ -541,11 +541,11 @@ to understand:
Tree-add == [popop not] [[pop] dipd Tree-new] [] [P [T] [Ee] [Te] cmp] genrec
-.. code:: python
+.. code:: ipython2
define('Tree-add == [popop not] [[pop] dipd Tree-new] [] [P [T] [Ee] [Te] cmp] genrec')
-.. code:: python
+.. code:: ipython2
J('[] 23 "b" Tree-add 88 "a" Tree-add 44 "c" Tree-add') # Still works.
@@ -685,14 +685,14 @@ Working backward:
Tree-iter == [not] [pop] roll< [dupdip rest rest] cons [step] genrec
-.. code:: python
+.. code:: ipython2
define('Tree-iter == [not] [pop] roll< [dupdip rest rest] cons [step] genrec')
Examples
~~~~~~~~
-.. code:: python
+.. code:: ipython2
J('[] [foo] Tree-iter') # It doesn't matter what F is as it won't be used.
@@ -702,7 +702,7 @@ Examples
-.. code:: python
+.. code:: ipython2
J("['b' 23 ['a' 88 [] []] ['c' 44 [] []]] [first] Tree-iter")
@@ -712,7 +712,7 @@ Examples
'b' 'a' 'c'
-.. code:: python
+.. code:: ipython2
J("['b' 23 ['a' 88 [] []] ['c' 44 [] []]] [second] Tree-iter")
@@ -731,7 +731,7 @@ to it will only occur once within it, and we can query it in
`:math:`O(\log_2 N)` `__
time.
-.. code:: python
+.. code:: ipython2
J('[] [3 9 5 2 8 6 7 8 4] [0 swap Tree-add] step')
@@ -741,11 +741,11 @@ time.
[3 0 [2 0 [] []] [9 0 [5 0 [4 0 [] []] [8 0 [6 0 [] [7 0 [] []]] []]] []]]
-.. code:: python
+.. code:: ipython2
define('to_set == [] swap [0 swap Tree-add] step')
-.. code:: python
+.. code:: ipython2
J('[3 9 5 2 8 6 7 8 4] to_set')
@@ -758,11 +758,11 @@ time.
And with that we can write a little program ``unique`` to remove
duplicate items from a list.
-.. code:: python
+.. code:: ipython2
define('unique == [to_set [first] Tree-iter] cons run')
-.. code:: python
+.. code:: ipython2
J('[3 9 3 5 2 9 8 8 8 6 2 7 8 4 3] unique') # Filter duplicate items.
@@ -872,7 +872,7 @@ Letâs do a little semantic factoring:
Now we can sort sequences.
-.. code:: python
+.. code:: ipython2
#define('Tree-iter-order == [not] [pop] [dup third] [[cons dip] dupdip [[first] dupdip] dip [rest rest rest first] dip i] genrec')
@@ -892,7 +892,7 @@ Now we can sort sequences.
-.. code:: python
+.. code:: ipython2
J('[3 9 5 2 8 6 7 8 4] to_set Tree-iter-order')
@@ -1070,7 +1070,7 @@ So:
Tree-get == [pop not] swap [] [P [T>] [E] [T<] cmp] genrec
-.. code:: python
+.. code:: ipython2
# I don't want to deal with name conflicts with the above so I'm inlining everything here.
# The original Joy system has "hide" which is a meta-command which allows you to use named
@@ -1088,7 +1088,7 @@ So:
] genrec
''')
-.. code:: python
+.. code:: ipython2
J('["gary" 23 [] []] "mike" [popd " not in tree" +] Tree-get')
@@ -1098,7 +1098,7 @@ So:
'mike not in tree'
-.. code:: python
+.. code:: ipython2
J('["gary" 23 [] []] "gary" [popop "err"] Tree-get')
@@ -1108,7 +1108,7 @@ So:
23
-.. code:: python
+.. code:: ipython2
J('''
@@ -1124,7 +1124,7 @@ So:
2
-.. code:: python
+.. code:: ipython2
J('''
@@ -1500,7 +1500,7 @@ Refactoring
By the standards of the code Iâve written so far, this is a *huge* Joy
program.
-.. code:: python
+.. code:: ipython2
DefinitionWrapper.add_definitions('''
first_two == uncons uncons pop
@@ -1519,7 +1519,7 @@ program.
Tree-Delete == [pop not] [pop] [R0] [R1] genrec
''', D)
-.. code:: python
+.. code:: ipython2
J("['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'c' Tree-Delete ")
@@ -1529,7 +1529,7 @@ program.
['a' 23 [] ['b' 88 [] []]]
-.. code:: python
+.. code:: ipython2
J("['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'b' Tree-Delete ")
@@ -1539,7 +1539,7 @@ program.
['a' 23 [] ['c' 44 [] []]]
-.. code:: python
+.. code:: ipython2
J("['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'a' Tree-Delete ")
@@ -1549,7 +1549,7 @@ program.
['b' 88 [] ['c' 44 [] []]]
-.. code:: python
+.. code:: ipython2
J("['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'der' Tree-Delete ")
@@ -1559,7 +1559,7 @@ program.
['a' 23 [] ['b' 88 [] ['c' 44 [] []]]]
-.. code:: python
+.. code:: ipython2
J('[] [4 2 3 1 6 7 5 ] [0 swap Tree-add] step')
@@ -1569,7 +1569,7 @@ program.
[4 0 [2 0 [1 0 [] []] [3 0 [] []]] [6 0 [5 0 [] []] [7 0 [] []]]]
-.. code:: python
+.. code:: ipython2
J("[4 0 [2 0 [1 0 [] []] [3 0 [] []]] [6 0 [5 0 [] []] [7 0 [] []]]] 3 Tree-Delete ")
@@ -1579,7 +1579,7 @@ program.
[4 0 [2 0 [1 0 [] []] []] [6 0 [5 0 [] []] [7 0 [] []]]]
-.. code:: python
+.. code:: ipython2
J("[4 0 [2 0 [1 0 [] []] [3 0 [] []]] [6 0 [5 0 [] []] [7 0 [] []]]] 4 Tree-Delete ")
diff --git a/docs/sphinx_docs/_build/html/_sources/notebooks/Quadratic.rst.txt b/docs/sphinx_docs/_build/html/_sources/notebooks/Quadratic.rst.txt
index 5afb8e2..3262e84 100644
--- a/docs/sphinx_docs/_build/html/_sources/notebooks/Quadratic.rst.txt
+++ b/docs/sphinx_docs/_build/html/_sources/notebooks/Quadratic.rst.txt
@@ -1,4 +1,4 @@
-.. code:: python
+.. code:: ipython2
from notebook_preamble import J, V, define
@@ -81,13 +81,13 @@ the variables:
The three arguments are to the left, so we can âchop offâ everything to
the right and say itâs the definition of the ``quadratic`` function:
-.. code:: python
+.. code:: ipython2
define('quadratic == over [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [/] cons app2')
Letâs try it out:
-.. code:: python
+.. code:: ipython2
J('3 1 1 quadratic')
@@ -102,7 +102,7 @@ lines are the ``dip`` and ``dipd`` combinators building the main program
by incorporating the values on the stack. Then that program runs and you
get the results. This is pretty typical of Joy code.
-.. code:: python
+.. code:: ipython2
V('-5 1 4 quadratic')
diff --git a/docs/sphinx_docs/_build/html/_sources/notebooks/Recursion_Combinators.rst.txt b/docs/sphinx_docs/_build/html/_sources/notebooks/Recursion_Combinators.rst.txt
index 2298cfd..9159882 100644
--- a/docs/sphinx_docs/_build/html/_sources/notebooks/Recursion_Combinators.rst.txt
+++ b/docs/sphinx_docs/_build/html/_sources/notebooks/Recursion_Combinators.rst.txt
@@ -1,4 +1,4 @@
-.. code:: python
+.. code:: ipython2
from notebook_preamble import D, DefinitionWrapper, J, V, define
@@ -80,7 +80,7 @@ is a recursive function ``H :: A -> C`` that converts a value of type
It may be helpful to see this function implemented in imperative Python
code.
-.. code:: python
+.. code:: ipython2
def hylomorphism(c, F, P, G):
'''Return a hylomorphism function H.'''
@@ -185,7 +185,7 @@ the left so we have a definition for ``hylomorphism``:
hylomorphism == [unit [pop] swoncat] dipd [dip] swoncat genrec
-.. code:: python
+.. code:: ipython2
define('hylomorphism == [unit [pop] swoncat] dipd [dip] swoncat genrec')
@@ -203,13 +203,13 @@ To sum a range of integers from 0 to *n* - 1:
- ``[G]`` is ``[-- dup]``
- ``[F]`` is ``[+]``
-.. code:: python
+.. code:: ipython2
define('triangular_number == [1 <=] 0 [-- dup] [+] hylomorphism')
Letâs try it:
-.. code:: python
+.. code:: ipython2
J('5 triangular_number')
@@ -219,7 +219,7 @@ Letâs try it:
10
-.. code:: python
+.. code:: ipython2
J('[0 1 2 3 4 5 6] [triangular_number] map')
@@ -391,10 +391,8 @@ values.
A == [P] [] [G] [swons] hylomorphism
-``range`` et. al.
-~~~~~~~~~~~~~~~~~
-
-An example of an anamorphism is the ``range`` function which generates the list of integers from 0 to *n* - 1 given *n*.
+``range`` et. al. An example of an anamorphism is the ``range`` function which generates the list of integers from 0 to *n* - 1 given *n*.
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Each of the above variations can be used to make four slightly different
``range`` functions.
@@ -407,11 +405,11 @@ Each of the above variations can be used to make four slightly different
H1 == [P] [pop c] [G] [dip F] genrec
== [0 <=] [pop []] [-- dup] [dip swons] genrec
-.. code:: python
+.. code:: ipython2
define('range == [0 <=] [] [-- dup] [swons] hylomorphism')
-.. code:: python
+.. code:: ipython2
J('5 range')
@@ -429,11 +427,11 @@ Each of the above variations can be used to make four slightly different
H2 == c swap [P] [pop] [G [F] dip] primrec
== [] swap [0 <=] [pop] [-- dup [swons] dip] primrec
-.. code:: python
+.. code:: ipython2
define('range_reverse == [] swap [0 <=] [pop] [-- dup [swons] dip] primrec')
-.. code:: python
+.. code:: ipython2
J('5 range_reverse')
@@ -451,11 +449,11 @@ Each of the above variations can be used to make four slightly different
H3 == [P] [pop c] [[G] dupdip] [dip F] genrec
== [0 <=] [pop []] [[--] dupdip] [dip swons] genrec
-.. code:: python
+.. code:: ipython2
define('ranger == [0 <=] [pop []] [[--] dupdip] [dip swons] genrec')
-.. code:: python
+.. code:: ipython2
J('5 ranger')
@@ -473,11 +471,11 @@ Each of the above variations can be used to make four slightly different
H4 == c swap [P] [pop] [[F] dupdip G ] primrec
== [] swap [0 <=] [pop] [[swons] dupdip --] primrec
-.. code:: python
+.. code:: ipython2
define('ranger_reverse == [] swap [0 <=] [pop] [[swons] dupdip --] primrec')
-.. code:: python
+.. code:: ipython2
J('5 ranger_reverse')
@@ -503,7 +501,7 @@ and makes some new value.
C == [not] c [uncons swap] [F] hylomorphism
-.. code:: python
+.. code:: ipython2
define('swuncons == uncons swap') # Awkward name.
@@ -513,11 +511,11 @@ An example of a catamorphism is the sum function.
sum == [not] 0 [swuncons] [+] hylomorphism
-.. code:: python
+.. code:: ipython2
define('sum == [not] 0 [swuncons] [+] hylomorphism')
-.. code:: python
+.. code:: ipython2
J('[5 4 3 2 1] sum')
@@ -533,7 +531,7 @@ The ``step`` combinator
The ``step`` combinator will usually be better to use than
``catamorphism``.
-.. code:: python
+.. code:: ipython2
J('[step] help')
@@ -562,11 +560,11 @@ The ``step`` combinator will usually be better to use than
-.. code:: python
+.. code:: ipython2
define('sum == 0 swap [+] step')
-.. code:: python
+.. code:: ipython2
J('[5 4 3 2 1] sum')
@@ -594,11 +592,11 @@ With:
G == --
P == 1 <=
-.. code:: python
+.. code:: ipython2
define('factorial == 1 swap [1 <=] [pop] [[*] dupdip --] primrec')
-.. code:: python
+.. code:: ipython2
J('5 factorial')
@@ -637,11 +635,11 @@ We would use:
G == rest dup
P == not
-.. code:: python
+.. code:: ipython2
define('tails == [] swap [not] [pop] [rest dup [swons] dip] primrec')
-.. code:: python
+.. code:: ipython2
J('[1 2 3] tails')
diff --git a/docs/sphinx_docs/_build/html/_sources/notebooks/Replacing.rst.txt b/docs/sphinx_docs/_build/html/_sources/notebooks/Replacing.rst.txt
index 02ecb3b..0f90445 100644
--- a/docs/sphinx_docs/_build/html/_sources/notebooks/Replacing.rst.txt
+++ b/docs/sphinx_docs/_build/html/_sources/notebooks/Replacing.rst.txt
@@ -9,14 +9,14 @@ dictionary. However, thereâs no function that does that. Adding a new
function to the dictionary is a meta-interpreter action, you have to do
it in Python, not Joy.
-.. code:: python
+.. code:: ipython2
from notebook_preamble import D, J, V
A long trace
------------
-.. code:: python
+.. code:: ipython2
V('[23 18] average')
@@ -81,7 +81,7 @@ An efficient ``sum`` function is already in the library. But for
``size`` we can use a âcompiledâ version hand-written in Python to speed
up evaluation and make the trace more readable.
-.. code:: python
+.. code:: ipython2
from joy.library import SimpleFunctionWrapper
from joy.utils.stack import iter_stack
@@ -99,7 +99,7 @@ up evaluation and make the trace more readable.
Now we replace the old version in the dictionary with the new version,
and re-evaluate the expression.
-.. code:: python
+.. code:: ipython2
D['size'] = size
@@ -108,7 +108,7 @@ A shorter trace
You can see that ``size`` now executes in a single step.
-.. code:: python
+.. code:: ipython2
V('[23 18] average')
diff --git a/docs/sphinx_docs/_build/html/_sources/notebooks/Square_Spiral.rst.txt b/docs/sphinx_docs/_build/html/_sources/notebooks/Square_Spiral.rst.txt
new file mode 100644
index 0000000..7b5e67a
--- /dev/null
+++ b/docs/sphinx_docs/_build/html/_sources/notebooks/Square_Spiral.rst.txt
@@ -0,0 +1,421 @@
+.. code:: ipython3
+
+ from notebook_preamble import J, V, define
+
+Square Spiral Example Joy Code
+==============================
+
+Here is the example of Joy code from the ``README`` file:
+
+::
+
+ [[[abs]ii <=][[<>][pop !-]||]&&][[!-][[++]][[--]]ifte dip][[pop !-][--][++]ifte]ifte
+
+It might seem unreadable but with a little familiarity it becomes just
+as legible as any other notation. Some layout helps:
+
+::
+
+ [ [[abs] ii <=]
+ [
+ [<>] [pop !-] ||
+ ] &&
+ ]
+ [[ !-] [[++]] [[--]] ifte dip]
+ [[pop !-] [--] [++] ifte ]
+ ifte
+
+This function accepts two integers on the stack and increments or
+decrements one of them such that the new pair of numbers is the next
+coordinate pair in a square spiral (like the kind used to construct an
+Ulam Spiral).
+
+Original Form
+-------------
+
+It's adapted from `the original code on
+StackOverflow `__:
+
+ If all you're trying to do is generate the first N points in the
+ spiral (without the original problem's constraint of masking to an N
+ x M region), the code becomes very simple:
+
+::
+
+ void spiral(const int N)
+ {
+ int x = 0;
+ int y = 0;
+ for(int i = 0; i < N; ++i)
+ {
+ cout << x << '\t' << y << '\n';
+ if(abs(x) <= abs(y) && (x != y || x >= 0))
+ x += ((y >= 0) ? 1 : -1);
+ else
+ y += ((x >= 0) ? -1 : 1);
+ }
+ }
+
+Translation to Joy
+------------------
+
+I'm going to make a function that take two ints (``x`` and ``y``) and
+generates the next pair, we'll turn it into a generator later using the
+``x`` combinator.
+
+First Boolean Predicate
+~~~~~~~~~~~~~~~~~~~~~~~
+
+We need a function that computes ``abs(x) <= abs(y)``, we can use ``ii``
+to apply ``abs`` to both values and then compare them with ``<=``:
+
+::
+
+ [abs] ii <=
+
+I've defined two short-circuiting Boolean combinators ``&&`` and ``||``
+that each accept two quoted predicate programs, run the first, and
+conditionally run the second only if required (to compute the final
+Boolean value). They run their predicate arguments ``nullary``.
+
+.. code:: ipython3
+
+ define('&& [nullary] cons [nullary [0]] dip branch')
+ define('|| [nullary] cons [nullary] dip [1] branch')
+
+Given those, we can define ``x != y || x >= 0`` as:
+
+::
+
+ [<>] [pop 0 >=] ||
+
+And ``(abs(x) <= abs(y) && (x != y || x >= 0))`` as:
+
+::
+
+ [[abs] ii <=] [[<>] [pop 0 >=] ||] &&
+
+It's a little rough, but, as I say, with a little familiarity it becomes
+legible.
+
+The Increment / Decrement Branches
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Turning to the branches of the main ``if`` statement:
+
+::
+
+ x += ((y >= 0) ? 1 : -1);
+
+Rewrite as a hybrid (pseudo-code) ``ifte`` expression:
+
+::
+
+ [y >= 0] [x += 1] [X -= 1] ifte
+
+Change each C phrase to Joy code:
+
+::
+
+ [0 >=] [[++] dip] [[--] dip] ifte
+
+Factor out the dip from each branch:
+
+::
+
+ [0 >=] [[++]] [[--]] ifte dip
+
+Similar logic applies to the other branch:
+
+::
+
+ y += ((x >= 0) ? -1 : 1);
+
+ [x >= 0] [y -= 1] [y += 1] ifte
+
+ [pop 0 >=] [--] [++] ifte
+
+"Not Negative"
+~~~~~~~~~~~~~~
+
+.. code:: ipython3
+
+ define('!- 0 >=')
+
+Putting the Pieces Together
+---------------------------
+
+We can assemble the three functions we just defined in quotes and give
+them them to the ``ifte`` combinator. With some arrangement to show off
+the symmetry of the two branches, we have:
+
+::
+
+ [[[abs] ii <=] [[<>] [pop !-] ||] &&]
+ [[ !-] [[++]] [[--]] ifte dip]
+ [[pop !-] [--] [++] ifte ]
+ ifte
+
+As I was writing this up I realized that, since the ``&&`` combinator
+doesn't consume the stack (below its quoted args), I can unquote the
+predicate, swap the branches, and use the ``branch`` combinator instead
+of ``ifte``:
+
+::
+
+ [[abs] ii <=] [[<>] [pop !-] ||] &&
+ [[pop !-] [--] [++] ifte ]
+ [[ !-] [[++]] [[--]] ifte dip]
+ branch
+
+.. code:: ipython3
+
+ define('spiral_next [[[abs] ii <=] [[<>] [pop !-] ||] &&] [[!-] [[++]] [[--]] ifte dip] [[pop !-] [--] [++] ifte] ifte')
+
+Let's try it out:
+
+.. code:: ipython3
+
+ J('0 0 spiral_next')
+
+
+.. parsed-literal::
+
+ 1 0
+
+
+.. code:: ipython3
+
+ J('1 0 spiral_next')
+
+
+.. parsed-literal::
+
+ 1 -1
+
+
+.. code:: ipython3
+
+ J('1 -1 spiral_next')
+
+
+.. parsed-literal::
+
+ 0 -1
+
+
+.. code:: ipython3
+
+ J('0 -1 spiral_next')
+
+
+.. parsed-literal::
+
+ -1 -1
+
+
+Turning it into a Generator with ``x``
+--------------------------------------
+
+It can be used with the x combinator to make a kind of generator for
+spiral square coordinates.
+
+We can use ``codireco`` to make a generator
+
+::
+
+ codireco ::= cons dip rest cons
+
+It will look like this:
+
+::
+
+ [value [F] codireco]
+
+Here's a trace of how it works:
+
+::
+
+ [0 [dup ++] codireco] . x
+ [0 [dup ++] codireco] . 0 [dup ++] codireco
+ [0 [dup ++] codireco] 0 . [dup ++] codireco
+ [0 [dup ++] codireco] 0 [dup ++] . codireco
+ [0 [dup ++] codireco] 0 [dup ++] . cons dip rest cons
+ [0 [dup ++] codireco] [0 dup ++] . dip rest cons
+ . 0 dup ++ [0 [dup ++] codireco] rest cons
+ 0 . dup ++ [0 [dup ++] codireco] rest cons
+ 0 0 . ++ [0 [dup ++] codireco] rest cons
+ 0 1 . [0 [dup ++] codireco] rest cons
+ 0 1 [0 [dup ++] codireco] . rest cons
+ 0 1 [[dup ++] codireco] . cons
+ 0 [1 [dup ++] codireco] .
+
+But first we have to change the ``spiral_next`` function to work on a
+quoted pair of integers, and leave a copy of the pair on the stack.
+From:
+
+::
+
+ y x spiral_next
+ ---------------------
+ y' x'
+
+to:
+
+::
+
+ [x y] [spiral_next] infra
+ -------------------------------
+ [x' y']
+
+.. code:: ipython3
+
+ J('[0 0] [spiral_next] infra')
+
+
+.. parsed-literal::
+
+ [0 1]
+
+
+So our generator is:
+
+::
+
+ [[x y] [dup [spiral_next] infra] codireco]
+
+Or rather:
+
+::
+
+ [[0 0] [dup [spiral_next] infra] codireco]
+
+There is a function ``make_generator`` that will build the generator for
+us out of the value and stepper function:
+
+::
+
+ [0 0] [dup [spiral_next] infra] make_generator
+ ----------------------------------------------------
+ [[0 0] [dup [spiral_next] infra] codireco]
+
+Here it is in action:
+
+.. code:: ipython3
+
+ J('[0 0] [dup [spiral_next] infra] make_generator x x x x pop')
+
+
+.. parsed-literal::
+
+ [0 0] [0 1] [-1 1] [-1 0]
+
+
+Four ``x`` combinators, four pairs of coordinates.
+
+Conclusion
+----------
+
+So that's an example of Joy code. It's a straightforward translation of
+the original. It's a little long for a single definition, you might
+break it up like so:
+
+::
+
+ _spn_P ::= [[abs] ii <=] [[<>] [pop !-] ||] &&
+
+ _spn_T ::= [ !-] [[++]] [[--]] ifte dip
+ _spn_E ::= [pop !-] [--] [++] ifte
+
+ spiral_next ::= _spn_P [_spn_E] [_spn_T] branch
+
+This way it's easy to see that the function is a branch with two
+quasi-symmetrical paths.
+
+We then used this function to make a simple generator of coordinate
+pairs, where the next pair in the series can be generated at any time by
+using the ``x`` combinator on the generator (which is just a quoted
+expression containing a copy of the current pair and the "stepper
+function" to generate the next pair from that.)
+
+.. code:: ipython3
+
+ define('_spn_P [[abs] ii <=] [[<>] [pop !-] ||] &&')
+ define('_spn_T [!-] [[++]] [[--]] ifte dip')
+ define('_spn_E [pop !-] [--] [++] ifte')
+ define('spiral_next _spn_P [_spn_E] [_spn_T] branch')
+
+.. code:: ipython3
+
+ V('23 18 spiral_next')
+
+
+.. parsed-literal::
+
+ . 23 18 spiral_next
+ 23 . 18 spiral_next
+ 23 18 . spiral_next
+ 23 18 . _spn_P [_spn_E] [_spn_T] branch
+ 23 18 . [[abs] ii <=] [[<>] [pop !-] ||] && [_spn_E] [_spn_T] branch
+ 23 18 [[abs] ii <=] . [[<>] [pop !-] ||] && [_spn_E] [_spn_T] branch
+ 23 18 [[abs] ii <=] [[<>] [pop !-] ||] . && [_spn_E] [_spn_T] branch
+ 23 18 [[abs] ii <=] [[<>] [pop !-] ||] . [nullary] cons [nullary [0]] dip branch [_spn_E] [_spn_T] branch
+ 23 18 [[abs] ii <=] [[<>] [pop !-] ||] [nullary] . cons [nullary [0]] dip branch [_spn_E] [_spn_T] branch
+ 23 18 [[abs] ii <=] [[[<>] [pop !-] ||] nullary] . [nullary [0]] dip branch [_spn_E] [_spn_T] branch
+ 23 18 [[abs] ii <=] [[[<>] [pop !-] ||] nullary] [nullary [0]] . dip branch [_spn_E] [_spn_T] branch
+ 23 18 [[abs] ii <=] . nullary [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 [[abs] ii <=] . [stack] dinfrirst [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 [[abs] ii <=] [stack] . dinfrirst [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 [[abs] ii <=] [stack] . dip infra first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 . stack [[abs] ii <=] infra first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 [18 23] . [[abs] ii <=] infra first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 [18 23] [[abs] ii <=] . infra first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 . [abs] ii <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 [abs] . ii <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 [abs] . [dip] dupdip i <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 [abs] [dip] . dupdip i <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 [abs] . dip [abs] i <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 . abs 18 [abs] i <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 . 18 [abs] i <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 . [abs] i <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 [abs] . i <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 . abs <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 . <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ False . [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ False [18 23] . swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 [False] . first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 False . [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 False [0] . [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
+ 23 18 False [0] [[[<>] [pop !-] ||] nullary] . branch [_spn_E] [_spn_T] branch
+ 23 18 . 0 [_spn_E] [_spn_T] branch
+ 23 18 0 . [_spn_E] [_spn_T] branch
+ 23 18 0 [_spn_E] . [_spn_T] branch
+ 23 18 0 [_spn_E] [_spn_T] . branch
+ 23 18 . _spn_E
+ 23 18 . [pop !-] [--] [++] ifte
+ 23 18 [pop !-] . [--] [++] ifte
+ 23 18 [pop !-] [--] . [++] ifte
+ 23 18 [pop !-] [--] [++] . ifte
+ 23 18 [pop !-] [--] [++] . [nullary not] dipd branch
+ 23 18 [pop !-] [--] [++] [nullary not] . dipd branch
+ 23 18 [pop !-] . nullary not [--] [++] branch
+ 23 18 [pop !-] . [stack] dinfrirst not [--] [++] branch
+ 23 18 [pop !-] [stack] . dinfrirst not [--] [++] branch
+ 23 18 [pop !-] [stack] . dip infra first not [--] [++] branch
+ 23 18 . stack [pop !-] infra first not [--] [++] branch
+ 23 18 [18 23] . [pop !-] infra first not [--] [++] branch
+ 23 18 [18 23] [pop !-] . infra first not [--] [++] branch
+ 23 18 . pop !- [18 23] swaack first not [--] [++] branch
+ 23 . !- [18 23] swaack first not [--] [++] branch
+ 23 . 0 >= [18 23] swaack first not [--] [++] branch
+ 23 0 . >= [18 23] swaack first not [--] [++] branch
+ True . [18 23] swaack first not [--] [++] branch
+ True [18 23] . swaack first not [--] [++] branch
+ 23 18 [True] . first not [--] [++] branch
+ 23 18 True . not [--] [++] branch
+ 23 18 False . [--] [++] branch
+ 23 18 False [--] . [++] branch
+ 23 18 False [--] [++] . branch
+ 23 18 . --
+ 23 17 .
+
diff --git a/docs/sphinx_docs/_build/html/_sources/notebooks/Treestep.rst.txt b/docs/sphinx_docs/_build/html/_sources/notebooks/Treestep.rst.txt
index 7f273d8..6b9081f 100644
--- a/docs/sphinx_docs/_build/html/_sources/notebooks/Treestep.rst.txt
+++ b/docs/sphinx_docs/_build/html/_sources/notebooks/Treestep.rst.txt
@@ -148,11 +148,11 @@ Working backwards:
Define ``treestep``
-------------------
-.. code:: python
+.. code:: ipython2
from notebook_preamble import D, J, V, define, DefinitionWrapper
-.. code:: python
+.. code:: ipython2
DefinitionWrapper.add_definitions('''
@@ -173,7 +173,7 @@ all nodes in a tree with this function:
sumtree == [pop 0] [] [sum +] treestep
-.. code:: python
+.. code:: ipython2
define('sumtree == [pop 0] [] [sum +] treestep')
@@ -185,7 +185,7 @@ Running this function on an empty tree value gives zero:
------------------------------------
0
-.. code:: python
+.. code:: ipython2
J('[] sumtree') # Empty tree.
@@ -205,7 +205,7 @@ Running it on a non-empty node:
n m +
n+m
-.. code:: python
+.. code:: ipython2
J('[23] sumtree') # No child trees.
@@ -215,7 +215,7 @@ Running it on a non-empty node:
23
-.. code:: python
+.. code:: ipython2
J('[23 []] sumtree') # Child tree, empty.
@@ -225,7 +225,7 @@ Running it on a non-empty node:
23
-.. code:: python
+.. code:: ipython2
J('[23 [2 [4]] [3]] sumtree') # Non-empty child trees.
@@ -235,7 +235,7 @@ Running it on a non-empty node:
32
-.. code:: python
+.. code:: ipython2
J('[23 [2 [8] [9]] [3] [4 []]] sumtree') # Etc...
@@ -245,7 +245,7 @@ Running it on a non-empty node:
49
-.. code:: python
+.. code:: ipython2
J('[23 [2 [8] [9]] [3] [4 []]] [pop 0] [] [cons sum] treestep') # Alternate "spelling".
@@ -255,7 +255,7 @@ Running it on a non-empty node:
49
-.. code:: python
+.. code:: ipython2
J('[23 [2 [8] [9]] [3] [4 []]] [] [pop 23] [cons] treestep') # Replace each node.
@@ -265,7 +265,7 @@ Running it on a non-empty node:
[23 [23 [23] [23]] [23] [23 []]]
-.. code:: python
+.. code:: ipython2
J('[23 [2 [8] [9]] [3] [4 []]] [] [pop 1] [cons] treestep')
@@ -275,7 +275,7 @@ Running it on a non-empty node:
[1 [1 [1] [1]] [1] [1 []]]
-.. code:: python
+.. code:: ipython2
J('[23 [2 [8] [9]] [3] [4 []]] [] [pop 1] [cons] treestep sumtree')
@@ -285,7 +285,7 @@ Running it on a non-empty node:
6
-.. code:: python
+.. code:: ipython2
J('[23 [2 [8] [9]] [3] [4 []]] [pop 0] [pop 1] [sum +] treestep') # Combine replace and sum into one function.
@@ -295,7 +295,7 @@ Running it on a non-empty node:
6
-.. code:: python
+.. code:: ipython2
J('[4 [3 [] [7]]] [pop 0] [pop 1] [sum +] treestep') # Combine replace and sum into one function.
@@ -339,7 +339,7 @@ Traversal
This doesnât quite work:
-.. code:: python
+.. code:: ipython2
J('[[3 0] [[2 0] [][]] [[9 0] [[5 0] [[4 0] [][]] [[8 0] [[6 0] [] [[7 0] [][]]][]]][]]] ["B"] [first] [i] treestep')
@@ -369,7 +369,7 @@ So:
[] [first] [flatten cons] treestep
-.. code:: python
+.. code:: ipython2
J('[[3 0] [[2 0] [] []] [[9 0] [[5 0] [[4 0] [] []] [[8 0] [[6 0] [] [[7 0] [] []]] []]] []]] [] [first] [flatten cons] treestep')
@@ -401,7 +401,7 @@ So:
[] [i roll< swons concat] [first] treestep
-.. code:: python
+.. code:: ipython2
J('[[3 0] [[2 0] [] []] [[9 0] [[5 0] [[4 0] [] []] [[8 0] [[6 0] [] [[7 0] [] []]] []]] []]] [] [uncons pop] [i roll< swons concat] treestep')
@@ -429,7 +429,7 @@ Plugging in our BTree structure:
[key value] N [left right] [K] C
-.. code:: python
+.. code:: ipython2
J('[["key" "value"] ["left"] ["right"] ] ["B"] ["N"] ["C"] treegrind')
@@ -444,7 +444,7 @@ Plugging in our BTree structure:
Iteration through the nodes
-.. code:: python
+.. code:: ipython2
J('[[3 0] [[2 0] [] []] [[9 0] [[5 0] [[4 0] [] []] [[8 0] [[6 0] [] [[7 0] [] []]] []]] []]] [pop] ["N"] [step] treegrind')
@@ -456,7 +456,7 @@ Iteration through the nodes
Sum the nodesâ keys.
-.. code:: python
+.. code:: ipython2
J('0 [[3 0] [[2 0] [] []] [[9 0] [[5 0] [[4 0] [] []] [[8 0] [[6 0] [] [[7 0] [] []]] []]] []]] [pop] [first +] [step] treegrind')
@@ -468,7 +468,7 @@ Sum the nodesâ keys.
Rebuild the tree using ``map`` (imitating ``treestep``.)
-.. code:: python
+.. code:: ipython2
J('[[3 0] [[2 0] [] []] [[9 0] [[5 0] [[4 0] [] []] [[8 0] [[6 0] [] [[7 0] [] []]] []]] []]] [] [[100 +] infra] [map cons] treegrind')
@@ -574,7 +574,7 @@ Putting it together
To me, that seems simpler than the ``genrec`` version.
-.. code:: python
+.. code:: ipython2
DefinitionWrapper.add_definitions('''
@@ -587,7 +587,7 @@ To me, that seems simpler than the ``genrec`` version.
''', D)
-.. code:: python
+.. code:: ipython2
J('''\
@@ -603,7 +603,7 @@ To me, that seems simpler than the ``genrec`` version.
15
-.. code:: python
+.. code:: ipython2
J('''\
diff --git a/docs/sphinx_docs/_build/html/_sources/notebooks/TypeChecking.rst.txt b/docs/sphinx_docs/_build/html/_sources/notebooks/TypeChecking.rst.txt
index 4e70a1a..cd85c67 100644
--- a/docs/sphinx_docs/_build/html/_sources/notebooks/TypeChecking.rst.txt
+++ b/docs/sphinx_docs/_build/html/_sources/notebooks/TypeChecking.rst.txt
@@ -1,7 +1,7 @@
Type Checking
=============
-.. code:: python
+.. code:: ipython2
import logging, sys
@@ -11,7 +11,7 @@ Type Checking
level=logging.INFO,
)
-.. code:: python
+.. code:: ipython2
from joy.utils.types import (
doc_from_stack_effect,
@@ -22,7 +22,7 @@ Type Checking
JoyTypeError,
)
-.. code:: python
+.. code:: ipython2
D = FUNCTIONS.copy()
del D['product']
@@ -31,7 +31,7 @@ Type Checking
An Example
----------
-.. code:: python
+.. code:: ipython2
fi, fo = infer(pop, swap, rolldown, rrest, ccons)[0]
@@ -46,7 +46,7 @@ An Example
40 ([a4 a5 ...1] a3 a2 a1 -- [a2 a3 ...1]) â
-.. code:: python
+.. code:: ipython2
print doc_from_stack_effect(fi, fo)
@@ -56,13 +56,13 @@ An Example
([a4 a5 ...1] a3 a2 a1 -- [a2 a3 ...1])
-.. code:: python
+.. code:: ipython2
from joy.parser import text_to_expression
from joy.utils.stack import stack_to_string
-.. code:: python
+.. code:: ipython2
e = text_to_expression('0 1 2 [3 4]') # reverse order
print stack_to_string(e)
@@ -73,7 +73,7 @@ An Example
[3 4] 2 1 0
-.. code:: python
+.. code:: ipython2
u = unify(e, fi)[0]
u
@@ -87,7 +87,7 @@ An Example
-.. code:: python
+.. code:: ipython2
g = reify(u, (fi, fo))
print doc_from_stack_effect(*g)
@@ -101,11 +101,11 @@ An Example
Unification Works âin Reverseâ
------------------------------
-.. code:: python
+.. code:: ipython2
e = text_to_expression('[2 3]')
-.. code:: python
+.. code:: ipython2
u = unify(e, fo)[0] # output side, not input side
u
@@ -119,7 +119,7 @@ Unification Works âin Reverseâ
-.. code:: python
+.. code:: ipython2
g = reify(u, (fi, fo))
print doc_from_stack_effect(*g)
@@ -133,7 +133,7 @@ Unification Works âin Reverseâ
Failing a Check
---------------
-.. code:: python
+.. code:: ipython2
fi, fo = infer(dup, mul)[0]
@@ -146,7 +146,7 @@ Failing a Check
31 (i1 -- i2) â
-.. code:: python
+.. code:: ipython2
e = text_to_expression('"two"')
print stack_to_string(e)
@@ -157,7 +157,7 @@ Failing a Check
'two'
-.. code:: python
+.. code:: ipython2
try:
unify(e, fi)
diff --git a/docs/sphinx_docs/_build/html/_sources/notebooks/Types.rst.txt b/docs/sphinx_docs/_build/html/_sources/notebooks/Types.rst.txt
index 8ca737d..4c91600 100644
--- a/docs/sphinx_docs/_build/html/_sources/notebooks/Types.rst.txt
+++ b/docs/sphinx_docs/_build/html/_sources/notebooks/Types.rst.txt
@@ -184,7 +184,7 @@ Compiling ``popâswapâroll<``
The simplest way to âcompileâ this function would be something like:
-.. code:: python
+.. code:: ipython2
def poswrd(s, e, d):
return rolldown(*swap(*pop(s, e, d)))
@@ -200,7 +200,7 @@ Looking ahead for a moment, from the stack effect comment:
We should be able to directly write out a Python function like:
-.. code:: python
+.. code:: ipython2
def poswrd(stack):
(_, (a, (b, (c, stack)))) = stack
@@ -393,7 +393,7 @@ And there you have it, the stack effect for
From this stack effect comment it should be possible to construct the
following Python code:
-.. code:: python
+.. code:: ipython2
def F(stack):
(_, (d, (c, ((a, (b, S0)), stack)))) = stack
@@ -408,7 +408,7 @@ Representing Stack Effect Comments in Python
Iâm going to use pairs of tuples of type descriptors, which will be
integers or tuples of type descriptors:
-.. code:: python
+.. code:: ipython2
roll_dn = (1, 2, 3), (2, 3, 1)
@@ -419,7 +419,7 @@ integers or tuples of type descriptors:
``compose()``
~~~~~~~~~~~~~
-.. code:: python
+.. code:: ipython2
def compose(f, g):
@@ -465,7 +465,7 @@ integers or tuples of type descriptors:
``unify()``
~~~~~~~~~~~
-.. code:: python
+.. code:: ipython2
def unify(u, v, s=None):
if s is None:
@@ -483,7 +483,7 @@ integers or tuples of type descriptors:
``update()``
~~~~~~~~~~~~
-.. code:: python
+.. code:: ipython2
def update(s, term):
if not isinstance(term, tuple):
@@ -493,7 +493,7 @@ integers or tuples of type descriptors:
``relabel()``
~~~~~~~~~~~~~
-.. code:: python
+.. code:: ipython2
def relabel(left, right):
return left, _1000(right)
@@ -517,7 +517,7 @@ integers or tuples of type descriptors:
``delabel()``
~~~~~~~~~~~~~
-.. code:: python
+.. code:: ipython2
def delabel(f):
s = {u: i for i, u in enumerate(sorted(_unique(f)))}
@@ -551,7 +551,7 @@ At last we put it all together in a function ``C()`` that accepts two
stack effect comments and returns their composition (or raises and
exception if they canât be composed due to type conflicts.)
-.. code:: python
+.. code:: ipython2
def C(f, g):
f, g = relabel(f, g)
@@ -560,7 +560,7 @@ exception if they canât be composed due to type conflicts.)
Letâs try it out.
-.. code:: python
+.. code:: ipython2
C(pop, swap)
@@ -573,7 +573,7 @@ Letâs try it out.
-.. code:: python
+.. code:: ipython2
C(C(pop, swap), roll_dn)
@@ -586,7 +586,7 @@ Letâs try it out.
-.. code:: python
+.. code:: ipython2
C(swap, roll_dn)
@@ -599,7 +599,7 @@ Letâs try it out.
-.. code:: python
+.. code:: ipython2
C(pop, C(swap, roll_dn))
@@ -612,7 +612,7 @@ Letâs try it out.
-.. code:: python
+.. code:: ipython2
poswrd = reduce(C, (pop, swap, roll_dn))
poswrd
@@ -633,13 +633,13 @@ Hereâs that trick to represent functions like ``rest`` and ``cons`` that
manipulate stacks. We use a cons-list of tuples and give the tails their
own numbers. Then everything above already works.
-.. code:: python
+.. code:: ipython2
rest = ((1, 2),), (2,)
cons = (1, 2), ((1, 2),)
-.. code:: python
+.. code:: ipython2
C(poswrd, rest)
@@ -671,7 +671,7 @@ The translation table, if you will, would be:
0: 0,
}
-.. code:: python
+.. code:: ipython2
F = reduce(C, (pop, swap, roll_dn, rest, rest, cons, cons))
@@ -699,11 +699,11 @@ Dealing with ``cons`` and ``uncons``
However, if we try to compose e.g. ``cons`` and ``uncons`` it wonât
work:
-.. code:: python
+.. code:: ipython2
uncons = ((1, 2),), (1, 2)
-.. code:: python
+.. code:: ipython2
try:
C(cons, uncons)
@@ -723,7 +723,7 @@ The problem is that the ``unify()`` function as written doesnât handle
the case when both terms are tuples. We just have to add a clause to
deal with this recursively:
-.. code:: python
+.. code:: ipython2
def unify(u, v, s=None):
if s is None:
@@ -753,7 +753,7 @@ deal with this recursively:
return s
-.. code:: python
+.. code:: ipython2
C(cons, uncons)
@@ -771,7 +771,7 @@ Part III: Compiling Yin Functions
Now consider the Python function we would like to derive:
-.. code:: python
+.. code:: ipython2
def F_python(stack):
(_, (d, (c, ((a, (b, S0)), stack)))) = stack
@@ -779,7 +779,7 @@ Now consider the Python function we would like to derive:
And compare it to the input stack effect comment tuple we just computed:
-.. code:: python
+.. code:: ipython2
F[0]
@@ -816,7 +816,7 @@ Eh?
And the return tuple
-.. code:: python
+.. code:: ipython2
F[1]
@@ -848,7 +848,7 @@ Python Identifiers
We want to substitute Python identifiers for the integers. Iâm going to
repurpose ``joy.parser.Symbol`` class for this:
-.. code:: python
+.. code:: ipython2
from collections import defaultdict
from joy.parser import Symbol
@@ -874,7 +874,7 @@ effect comment tuples to reasonable text format. There are some details
in how this code works that related to stuff later in the notebook, so
you should skip it for now and read it later if youâre interested.
-.. code:: python
+.. code:: ipython2
def doc_from_stack_effect(inputs, outputs):
return '(%s--%s)' % (
@@ -914,7 +914,7 @@ Now we can write a compiler function to emit Python source code. (The
underscore suffix distiguishes it from the built-in ``compile()``
function.)
-.. code:: python
+.. code:: ipython2
def compile_(name, f, doc=None):
if doc is None:
@@ -932,7 +932,7 @@ function.)
Here it is in action:
-.. code:: python
+.. code:: ipython2
source = compile_('F', F)
@@ -949,7 +949,7 @@ Here it is in action:
Compare:
-.. code:: python
+.. code:: ipython2
def F_python(stack):
(_, (d, (c, ((a, (b, S0)), stack)))) = stack
@@ -957,7 +957,7 @@ Compare:
Next steps:
-.. code:: python
+.. code:: ipython2
L = {}
@@ -976,16 +976,16 @@ Next steps:
Letâs try it out:
-.. code:: python
+.. code:: ipython2
from notebook_preamble import D, J, V
from joy.library import SimpleFunctionWrapper
-.. code:: python
+.. code:: ipython2
D['F'] = SimpleFunctionWrapper(L['F'])
-.. code:: python
+.. code:: ipython2
J('[4 5 ...] 2 3 1 F')
@@ -1012,7 +1012,7 @@ Compiling Library Functions
We can use ``compile_()`` to generate many primitives in the library
from their stack effect comments:
-.. code:: python
+.. code:: ipython2
def defs():
@@ -1036,7 +1036,7 @@ from their stack effect comments:
return locals()
-.. code:: python
+.. code:: ipython2
for name, stack_effect_comment in sorted(defs().items()):
print
@@ -1205,7 +1205,7 @@ Python class hierarchy of Joy types and use the ``issubclass()`` method
to establish domain ordering, as well as other handy behaviour that will
make it fairly easy to reuse most of the code above.
-.. code:: python
+.. code:: ipython2
class AnyJoyType(object):
@@ -1251,14 +1251,14 @@ make it fairly easy to reuse most of the code above.
Mess with it a little:
-.. code:: python
+.. code:: ipython2
from itertools import permutations
âAnyâ types can be specialized to numbers and stacks, but not vice
versa:
-.. code:: python
+.. code:: ipython2
for a, b in permutations((A[0], N[0], S[0]), 2):
print a, '>=', b, '->', a >= b
@@ -1278,7 +1278,7 @@ Our crude `Numerical
Tower `__ of *numbers* >
*floats* > *integers* works as well (but weâre not going to use it yet):
-.. code:: python
+.. code:: ipython2
for a, b in permutations((A[0], N[0], FloatJoyType(0), IntJoyType(0)), 2):
print a, '>=', b, '->', a >= b
@@ -1303,13 +1303,13 @@ Tower `__ of *numbers* >
Typing ``sqr``
~~~~~~~~~~~~~~
-.. code:: python
+.. code:: ipython2
dup = (A[1],), (A[1], A[1])
mul = (N[1], N[2]), (N[3],)
-.. code:: python
+.. code:: ipython2
dup
@@ -1322,7 +1322,7 @@ Typing ``sqr``
-.. code:: python
+.. code:: ipython2
mul
@@ -1340,7 +1340,7 @@ Modifying the Inferencer
Re-labeling still works fine:
-.. code:: python
+.. code:: ipython2
foo = relabel(dup, mul)
@@ -1361,7 +1361,7 @@ Re-labeling still works fine:
The ``delabel()`` function needs an overhaul. It now has to keep track
of how many labels of each domain it has âseenâ.
-.. code:: python
+.. code:: ipython2
from collections import Counter
@@ -1383,7 +1383,7 @@ of how many labels of each domain it has âseenâ.
return tuple(delabel(inner, seen, c) for inner in f)
-.. code:: python
+.. code:: ipython2
delabel(foo)
@@ -1399,7 +1399,7 @@ of how many labels of each domain it has âseenâ.
``unify()`` version 3
^^^^^^^^^^^^^^^^^^^^^
-.. code:: python
+.. code:: ipython2
def unify(u, v, s=None):
if s is None:
@@ -1449,7 +1449,7 @@ of how many labels of each domain it has âseenâ.
Rewrite the stack effect comments:
-.. code:: python
+.. code:: ipython2
def defs():
@@ -1503,11 +1503,11 @@ Rewrite the stack effect comments:
return locals()
-.. code:: python
+.. code:: ipython2
DEFS = defs()
-.. code:: python
+.. code:: ipython2
for name, stack_effect_comment in sorted(DEFS.items()):
print name, '=', doc_from_stack_effect(*stack_effect_comment)
@@ -1543,14 +1543,14 @@ Rewrite the stack effect comments:
uncons = ([a1 .1.] -- a1 [.1.])
-.. code:: python
+.. code:: ipython2
globals().update(DEFS)
Compose ``dup`` and ``mul``
^^^^^^^^^^^^^^^^^^^^^^^^^^^
-.. code:: python
+.. code:: ipython2
C(dup, mul)
@@ -1565,7 +1565,7 @@ Compose ``dup`` and ``mul``
Revisit the ``F`` function, works fine.
-.. code:: python
+.. code:: ipython2
F = reduce(C, (pop, swap, rolldown, rest, rest, cons, cons))
F
@@ -1579,7 +1579,7 @@ Revisit the ``F`` function, works fine.
-.. code:: python
+.. code:: ipython2
print doc_from_stack_effect(*F)
@@ -1592,12 +1592,12 @@ Revisit the ``F`` function, works fine.
Some otherwise inefficient functions are no longer to be feared. We can
also get the effect of combinators in some limited cases.
-.. code:: python
+.. code:: ipython2
def neato(*funcs):
print doc_from_stack_effect(*reduce(C, funcs))
-.. code:: python
+.. code:: ipython2
# e.g. [swap] dip
neato(rollup, swap, rolldown)
@@ -1608,7 +1608,7 @@ also get the effect of combinators in some limited cases.
(a1 a2 a3 -- a2 a1 a3)
-.. code:: python
+.. code:: ipython2
# e.g. [popop] dipd
neato(popdd, rolldown, pop)
@@ -1619,7 +1619,7 @@ also get the effect of combinators in some limited cases.
(a1 a2 a3 a4 -- a3 a4)
-.. code:: python
+.. code:: ipython2
# Reverse the order of the top three items.
neato(rollup, swap)
@@ -1636,7 +1636,7 @@ also get the effect of combinators in some limited cases.
Because the type labels represent themselves as valid Python identifiers
the ``compile_()`` function doesnât need to generate them anymore:
-.. code:: python
+.. code:: ipython2
def compile_(name, f, doc=None):
inputs, outputs = f
@@ -1652,7 +1652,7 @@ the ``compile_()`` function doesnât need to generate them anymore:
%s = stack
return %s''' % (name, doc, i, o)
-.. code:: python
+.. code:: ipython2
print compile_('F', F)
@@ -1668,7 +1668,7 @@ the ``compile_()`` function doesnât need to generate them anymore:
But it cannot magically create new functions that involve e.g. math and
such. Note that this is *not* a ``sqr`` function implementation:
-.. code:: python
+.. code:: ipython2
print compile_('sqr', C(dup, mul))
@@ -1696,7 +1696,7 @@ The functions that *can* be compiled are the ones that have only
``AnyJoyType`` and ``StackJoyType`` labels in their stack effect
comments. We can write a function to check that:
-.. code:: python
+.. code:: ipython2
from itertools import imap
@@ -1704,7 +1704,7 @@ comments. We can write a function to check that:
def compilable(f):
return isinstance(f, tuple) and all(imap(compilable, f)) or stacky(f)
-.. code:: python
+.. code:: ipython2
for name, stack_effect_comment in sorted(defs().items()):
if compilable(stack_effect_comment):
@@ -1828,7 +1828,7 @@ the âtruthinessâ of ``StackJoyType`` to false to let e.g.
``joy.utils.stack.concat`` work with our stack effect comment cons-list
tuples.)
-.. code:: python
+.. code:: ipython2
def compose(f, g):
(f_in, f_out), (g_in, g_out) = f, g
@@ -1840,7 +1840,7 @@ tuples.)
I donât want to rewrite all the defs myself, so Iâll write a little
conversion function instead. This is programmerâs laziness.
-.. code:: python
+.. code:: ipython2
def sequence_to_stack(seq, stack=StackJoyType(23)):
for item in seq: stack = item, stack
@@ -1854,7 +1854,7 @@ conversion function instead. This is programmerâs laziness.
NEW_DEFS['swaack'] = (S[1], S[0]), (S[0], S[1])
globals().update(NEW_DEFS)
-.. code:: python
+.. code:: ipython2
C(stack, uncons)
@@ -1867,7 +1867,7 @@ conversion function instead. This is programmerâs laziness.
-.. code:: python
+.. code:: ipython2
reduce(C, (stack, uncons, uncons))
@@ -1887,7 +1887,7 @@ The display function should be changed too.
Clunky junk, but it will suffice for now.
-.. code:: python
+.. code:: ipython2
def doc_from_stack_effect(inputs, outputs):
switch = [False] # Do we need to display the '...' for the rest of the main stack?
@@ -1935,7 +1935,7 @@ Clunky junk, but it will suffice for now.
a.append(end)
return '[%s]' % ' '.join(a)
-.. code:: python
+.. code:: ipython2
for name, stack_effect_comment in sorted(NEW_DEFS.items()):
print name, '=', doc_from_stack_effect(*stack_effect_comment)
@@ -1973,7 +1973,7 @@ Clunky junk, but it will suffice for now.
uncons = ([a1 .1.] -- a1 [.1.])
-.. code:: python
+.. code:: ipython2
print ; print doc_from_stack_effect(*stack)
print ; print doc_from_stack_effect(*C(stack, uncons))
@@ -1993,7 +1993,7 @@ Clunky junk, but it will suffice for now.
(... a1 -- ... a1 [a1 ...])
-.. code:: python
+.. code:: ipython2
print doc_from_stack_effect(*C(ccons, stack))
@@ -2003,7 +2003,7 @@ Clunky junk, but it will suffice for now.
(... a2 a1 [.1.] -- ... [a2 a1 .1.] [[a2 a1 .1.] ...])
-.. code:: python
+.. code:: ipython2
Q = C(ccons, stack)
@@ -2024,7 +2024,7 @@ Clunky junk, but it will suffice for now.
This makes the ``compile_()`` function pretty simple as the stack effect
comments are now already in the form needed for the Python code:
-.. code:: python
+.. code:: ipython2
def compile_(name, f, doc=None):
i, o = f
@@ -2035,7 +2035,7 @@ comments are now already in the form needed for the Python code:
%s = stack
return %s''' % (name, doc, i, o)
-.. code:: python
+.. code:: ipython2
print compile_('Q', Q)
@@ -2053,12 +2053,12 @@ comments are now already in the form needed for the Python code:
-.. code:: python
+.. code:: ipython2
unstack = (S[1], S[0]), S[1]
enstacken = S[0], (S[0], S[1])
-.. code:: python
+.. code:: ipython2
print doc_from_stack_effect(*unstack)
@@ -2068,7 +2068,7 @@ comments are now already in the form needed for the Python code:
([.1.] --)
-.. code:: python
+.. code:: ipython2
print doc_from_stack_effect(*enstacken)
@@ -2078,7 +2078,7 @@ comments are now already in the form needed for the Python code:
(-- [.0.])
-.. code:: python
+.. code:: ipython2
print doc_from_stack_effect(*C(cons, unstack))
@@ -2088,7 +2088,7 @@ comments are now already in the form needed for the Python code:
(a1 [.1.] -- a1)
-.. code:: python
+.. code:: ipython2
print doc_from_stack_effect(*C(cons, enstacken))
@@ -2098,7 +2098,7 @@ comments are now already in the form needed for the Python code:
(a1 [.1.] -- [[a1 .1.] .2.])
-.. code:: python
+.. code:: ipython2
C(cons, unstack)
@@ -2117,7 +2117,7 @@ Part VI: Multiple Stack Effects
â¦
-.. code:: python
+.. code:: ipython2
class IntJoyType(NumberJoyType): prefix = 'i'
@@ -2125,7 +2125,7 @@ Part VI: Multiple Stack Effects
F = map(FloatJoyType, _R)
I = map(IntJoyType, _R)
-.. code:: python
+.. code:: ipython2
muls = [
((I[2], (I[1], S[0])), (I[3], S[0])),
@@ -2134,7 +2134,7 @@ Part VI: Multiple Stack Effects
((F[2], (F[1], S[0])), (F[3], S[0])),
]
-.. code:: python
+.. code:: ipython2
for f in muls:
print doc_from_stack_effect(*f)
@@ -2148,7 +2148,7 @@ Part VI: Multiple Stack Effects
(f1 f2 -- f3)
-.. code:: python
+.. code:: ipython2
for f in muls:
try:
@@ -2164,7 +2164,7 @@ Part VI: Multiple Stack Effects
(a1 -- a1 a1) (f1 f2 -- f3) (f1 -- f2)
-.. code:: python
+.. code:: ipython2
from itertools import product
@@ -2180,7 +2180,7 @@ Part VI: Multiple Stack Effects
def MC(F, G):
return sorted(set(meta_compose(F, G)))
-.. code:: python
+.. code:: ipython2
for f in MC([dup], [mul]):
print doc_from_stack_effect(*f)
@@ -2191,7 +2191,7 @@ Part VI: Multiple Stack Effects
(n1 -- n2)
-.. code:: python
+.. code:: ipython2
for f in MC([dup], muls):
print doc_from_stack_effect(*f)
@@ -2264,7 +2264,7 @@ Giving us two unifiers:
{c: a, d: b, .1.: .0.}
{c: a, d: e, .1.: A* b .0.}
-.. code:: python
+.. code:: ipython2
class KleeneStar(object):
@@ -2314,7 +2314,7 @@ Giving us two unifiers:
Can now return multiple resultsâ¦
-.. code:: python
+.. code:: ipython2
def unify(u, v, s=None):
if s is None:
@@ -2386,7 +2386,7 @@ Can now return multiple resultsâ¦
def stacky(thing):
return thing.__class__ in {AnyJoyType, StackJoyType}
-.. code:: python
+.. code:: ipython2
a = (As[1], S[1])
a
@@ -2400,7 +2400,7 @@ Can now return multiple resultsâ¦
-.. code:: python
+.. code:: ipython2
b = (A[1], S[2])
b
@@ -2414,7 +2414,7 @@ Can now return multiple resultsâ¦
-.. code:: python
+.. code:: ipython2
for result in unify(b, a):
print result, '->', update(result, a), update(result, b)
@@ -2426,7 +2426,7 @@ Can now return multiple resultsâ¦
{a1: a10001, s2: (a1*, s1)} -> (a1*, s1) (a10001, (a1*, s1))
-.. code:: python
+.. code:: ipython2
for result in unify(a, b):
print result, '->', update(result, a), update(result, b)
@@ -2446,7 +2446,7 @@ Can now return multiple resultsâ¦
(a1*, s1) [a1*] (a2, (a1*, s1)) [a2 a1*]
-.. code:: python
+.. code:: ipython2
sum_ = ((Ns[1], S[1]), S[0]), (N[0], S[0])
@@ -2458,7 +2458,7 @@ Can now return multiple resultsâ¦
([n1* .1.] -- n0)
-.. code:: python
+.. code:: ipython2
f = (N[1], (N[2], (N[3], S[1]))), S[0]
@@ -2470,7 +2470,7 @@ Can now return multiple resultsâ¦
(-- [n1 n2 n3 .1.])
-.. code:: python
+.. code:: ipython2
for result in unify(sum_[0], f):
print result, '->', update(result, sum_[1])
@@ -2489,7 +2489,7 @@ Can now return multiple resultsâ¦
This function has to be modified to yield multiple results.
-.. code:: python
+.. code:: ipython2
def compose(f, g):
(f_in, f_out), (g_in, g_out) = f, g
@@ -2501,7 +2501,7 @@ This function has to be modified to yield multiple results.
-.. code:: python
+.. code:: ipython2
def meta_compose(F, G):
for f, g in product(F, G):
@@ -2517,7 +2517,7 @@ This function has to be modified to yield multiple results.
for fg in compose(f, g):
yield delabel(fg)
-.. code:: python
+.. code:: ipython2
for f in MC([dup], muls):
print doc_from_stack_effect(*f)
@@ -2529,7 +2529,7 @@ This function has to be modified to yield multiple results.
(i1 -- i2)
-.. code:: python
+.. code:: ipython2
@@ -2542,7 +2542,7 @@ This function has to be modified to yield multiple results.
([n1* .1.] -- [n1* .1.] n1)
-.. code:: python
+.. code:: ipython2
@@ -2556,7 +2556,7 @@ This function has to be modified to yield multiple results.
(n1 [n1* .1.] -- n2)
-.. code:: python
+.. code:: ipython2
sum_ = (((N[1], (Ns[1], S[1])), S[0]), (N[0], S[0]))
print doc_from_stack_effect(*cons),
@@ -2571,7 +2571,7 @@ This function has to be modified to yield multiple results.
(a1 [.1.] -- [a1 .1.]) ([n1 n1* .1.] -- n0) (n1 [n1* .1.] -- n2)
-.. code:: python
+.. code:: ipython2
a = (A[4], (As[1], (A[3], S[1])))
a
@@ -2585,7 +2585,7 @@ This function has to be modified to yield multiple results.
-.. code:: python
+.. code:: ipython2
b = (A[1], (A[2], S[2]))
b
@@ -2599,7 +2599,7 @@ This function has to be modified to yield multiple results.
-.. code:: python
+.. code:: ipython2
for result in unify(b, a):
print result
@@ -2611,7 +2611,7 @@ This function has to be modified to yield multiple results.
{a1: a4, s2: (a1*, (a3, s1)), a2: a10003}
-.. code:: python
+.. code:: ipython2
for result in unify(a, b):
print result
@@ -2681,7 +2681,7 @@ We need a type variable for Joy functions that can go in our expressions
and be used by the hybrid inferencer/interpreter. They have to store a
name and a list of stack effects.
-.. code:: python
+.. code:: ipython2
class FunctionJoyType(AnyJoyType):
@@ -2703,14 +2703,14 @@ Specialized for Simple Functions and Combinators
For non-combinator functions the stack effects list contains stack
effect comments (represented by pairs of cons-lists as described above.)
-.. code:: python
+.. code:: ipython2
class SymbolJoyType(FunctionJoyType):
prefix = 'F'
For combinators the list contains Python functions.
-.. code:: python
+.. code:: ipython2
class CombinatorJoyType(FunctionJoyType):
@@ -2731,7 +2731,7 @@ For combinators the list contains Python functions.
For simple combinators that have only one effect (like ``dip``) you only
need one function and it can be the combinator itself.
-.. code:: python
+.. code:: ipython2
import joy.library
@@ -2741,7 +2741,7 @@ For combinators that can have more than one effect (like ``branch``) you
have to write functions that each implement the action of one of the
effects.
-.. code:: python
+.. code:: ipython2
def branch_true(stack, expression, dictionary):
(then, (else_, (flag, stack))) = stack
@@ -2771,7 +2771,7 @@ updated along with the stack effects after doing unification or we risk
losing useful information. This was a straightforward, if awkward,
modification to the call structure of ``meta_compose()`` et. al.
-.. code:: python
+.. code:: ipython2
ID = S[0], S[0] # Identity function.
@@ -2833,7 +2833,7 @@ cruft to convert the definitions in ``DEFS`` to the new
``SymbolJoyType`` objects, and some combinators. Here is an example of
output from the current code :
-.. code:: python
+.. code:: ipython2
1/0 # (Don't try to run this cell! It's not going to work. This is "read only" code heh..)
@@ -2956,7 +2956,7 @@ module. But if youâre interested in all that you should just use Prolog!
Anyhow, type *checking* is a few easy steps away.
-.. code:: python
+.. code:: ipython2
def _ge(self, other):
return (issubclass(other.__class__, self.__class__)
diff --git a/docs/sphinx_docs/_build/html/_sources/notebooks/Zipper.rst.txt b/docs/sphinx_docs/_build/html/_sources/notebooks/Zipper.rst.txt
index c44343a..dc4f996 100644
--- a/docs/sphinx_docs/_build/html/_sources/notebooks/Zipper.rst.txt
+++ b/docs/sphinx_docs/_build/html/_sources/notebooks/Zipper.rst.txt
@@ -10,7 +10,7 @@ Huet `__ out
of sequences.
-.. code:: python
+.. code:: ipython2
J('[1 [2 [3 4 25 6] 7] 8]')
@@ -54,14 +54,14 @@ show the trace so you can see how it works. If we were going to use
these a lot it would make sense to write Python versions for efficiency,
but see below.
-.. code:: python
+.. code:: ipython2
define('z-down == [] swap uncons swap')
define('z-up == swons swap shunt')
define('z-right == [swons] cons dip uncons swap')
define('z-left == swons [uncons swap] dip swap')
-.. code:: python
+.. code:: ipython2
V('[1 [2 [3 4 25 6] 7] 8] z-down')
@@ -77,7 +77,7 @@ but see below.
[] [[2 [3 4 25 6] 7] 8] 1 .
-.. code:: python
+.. code:: ipython2
V('[] [[2 [3 4 25 6] 7] 8] 1 z-right')
@@ -101,7 +101,7 @@ but see below.
[1] [8] [2 [3 4 25 6] 7] .
-.. code:: python
+.. code:: ipython2
J('[1] [8] [2 [3 4 25 6] 7] z-down')
@@ -111,7 +111,7 @@ but see below.
[1] [8] [] [[3 4 25 6] 7] 2
-.. code:: python
+.. code:: ipython2
J('[1] [8] [] [[3 4 25 6] 7] 2 z-right')
@@ -121,7 +121,7 @@ but see below.
[1] [8] [2] [7] [3 4 25 6]
-.. code:: python
+.. code:: ipython2
J('[1] [8] [2] [7] [3 4 25 6] z-down')
@@ -131,7 +131,7 @@ but see below.
[1] [8] [2] [7] [] [4 25 6] 3
-.. code:: python
+.. code:: ipython2
J('[1] [8] [2] [7] [] [4 25 6] 3 z-right')
@@ -141,7 +141,7 @@ but see below.
[1] [8] [2] [7] [3] [25 6] 4
-.. code:: python
+.. code:: ipython2
J('[1] [8] [2] [7] [3] [25 6] 4 z-right')
@@ -151,7 +151,7 @@ but see below.
[1] [8] [2] [7] [4 3] [6] 25
-.. code:: python
+.. code:: ipython2
J('[1] [8] [2] [7] [4 3] [6] 25 sqr')
@@ -161,7 +161,7 @@ but see below.
[1] [8] [2] [7] [4 3] [6] 625
-.. code:: python
+.. code:: ipython2
V('[1] [8] [2] [7] [4 3] [6] 625 z-up')
@@ -184,7 +184,7 @@ but see below.
[1] [8] [2] [7] [3 4 625 6] .
-.. code:: python
+.. code:: ipython2
J('[1] [8] [2] [7] [3 4 625 6] z-up')
@@ -194,7 +194,7 @@ but see below.
[1] [8] [2 [3 4 625 6] 7]
-.. code:: python
+.. code:: ipython2
J('[1] [8] [2 [3 4 625 6] 7] z-up')
@@ -210,7 +210,7 @@ but see below.
In Joy we have the ``dip`` and ``infra`` combinators which can âtargetâ
or âaddressâ any particular item in a Joy tree structure.
-.. code:: python
+.. code:: ipython2
V('[1 [2 [3 4 25 6] 7] 8] [[[[[[sqr] dipd] infra] dip] infra] dip] infra')
@@ -270,13 +270,13 @@ been embedded in a nested series of quoted programs, e.g.:
The ``Z`` function isnât hard to make.
-.. code:: python
+.. code:: ipython2
define('Z == [[] cons cons] step i')
Here it is in action in a simplified scenario.
-.. code:: python
+.. code:: ipython2
V('1 [2 3 4] Z')
@@ -314,7 +314,7 @@ Here it is in action in a simplified scenario.
And here it is doing the main thing.
-.. code:: python
+.. code:: ipython2
J('[1 [2 [3 4 25 6] 7] 8] [sqr] [dip dip infra dip infra dip infra] Z')
diff --git a/docs/sphinx_docs/_build/html/_sources/notebooks/index.rst.txt b/docs/sphinx_docs/_build/html/_sources/notebooks/index.rst.txt
index c14aafa..dbb23a5 100644
--- a/docs/sphinx_docs/_build/html/_sources/notebooks/index.rst.txt
+++ b/docs/sphinx_docs/_build/html/_sources/notebooks/index.rst.txt
@@ -16,6 +16,7 @@ These essays are adapted from Jupyter notebooks. I hope to have those hosted so
Treestep
Generator_Programs
Newton-Raphson
+ Square_Spiral
Zipper
Types
TypeChecking
diff --git a/docs/sphinx_docs/_build/html/index.html b/docs/sphinx_docs/_build/html/index.html
index 4e3c3be..24307ce 100644
--- a/docs/sphinx_docs/_build/html/index.html
+++ b/docs/sphinx_docs/_build/html/index.html
@@ -54,6 +54,29 @@ additional joy interpreter (the binary in the archive from La Trobe seems
to run just fine on my modern Linux machine!) But I also hope that you
can read and understand the Python code and play with the implementation
itself.
+
+Example Code
+Here is an example of Joy code:
+ [[[abs]ii <=][[<>][pop !-]||]&&][[!-][[++]][[--]]ifte dip][[pop !-][--][++]ifte]ifte
+
+
+It might seem unreadable but with a little familiarity it becomes just as
+legible as any other notation. Some layout helps:
+ [ [[abs] ii <=]
+ [
+ [<>] [pop !-] ||
+ ] &&
+]
+[[ !-] [[++]] [[--]] ifte dip]
+[[pop !-] [--] [++] ifte ]
+ifte
+
+
+This function accepts two integers on the stack and increments or
+decrements one of them such that the new pair of numbers is the next
+coordinate pair in a square spiral (like the kind used to construct an
+Ulam Spiral). For more information see Square Spiral Example Joy Code
+
Implementation
-from functools import partial as curry
+from functools import partial as curry
from itertools import product
Ï
and λ
The empty set and the set of just the empty string.
-phi = frozenset () # Ï
+phi = frozenset () # Ï
y = frozenset ({ '' }) # λ
@@ -115,7 +115,7 @@ illustrate the algorithm and because you can represent any other
alphabet with two symbols (if you had to.)
I chose the names O
and l
(uppercase âoâ and lowercase âLâ) to
look like 0
and 1
(zero and one) respectively.
-syms = O , l = frozenset ({ '0' }), frozenset ({ '1' })
+syms = O , l = frozenset ({ '0' }), frozenset ({ '1' })
@@ -133,7 +133,7 @@ expression is one of:
Where R
and S
stand for regular expressions .
-AND , CONS , KSTAR , NOT , OR = 'and cons * not or' . split () # Tags are just strings.
+AND , CONS , KSTAR , NOT , OR = 'and cons * not or' . split () # Tags are just strings.
Because they are formed of frozenset
, tuple
and str
objects
@@ -141,7 +141,7 @@ only, these datastructures are immutable.
String Representation of RE Datastructures
-def stringy ( re ):
+def stringy ( re ):
'''
Return a nice string repr for a regular expression datastructure.
'''
@@ -180,10 +180,10 @@ only, these datastructures are immutable.
-I = ( KSTAR , ( OR , O , l ))
+
-print stringy ( I )
+
.
@@ -198,13 +198,13 @@ only, these datastructures are immutable.
Note that it contains one of everything.
-a = ( CONS , I , ( CONS , l , ( CONS , l , ( CONS , l , I ))))
+a = ( CONS , I , ( CONS , l , ( CONS , l , ( CONS , l , I ))))
b = ( CONS , I , ( CONS , O , l ))
c = ( CONS , l , ( KSTAR , l ))
it = ( AND , a , ( NOT , ( OR , b , c )))
-print stringy ( it )
+
( . 111. ) & (( . 01 | 11 * ) ')
@@ -214,7 +214,7 @@ only, these datastructures are immutable.
nully()
Letâs get that auxiliary predicate function δ
out of the way.
-def nully ( R ):
+def nully ( R ):
'''
δ - Return λ if λ â R otherwise Ï.
'''
@@ -252,7 +252,7 @@ only, these datastructures are immutable.
This is the straightforward version with no âcompactionâ. It works fine,
but does waaaay too much work because the expressions grow each
derivation.
-def D ( symbol ):
+def D ( symbol ):
def derv ( R ):
@@ -296,7 +296,7 @@ derivation.
Compaction Rules
-def _compaction_rule ( relation , one , zero , a , b ):
+def _compaction_rule ( relation , one , zero , a , b ):
return (
b if a == one else # R*1 = 1*R = R
a if b == one else
@@ -306,7 +306,7 @@ derivation.
An elegant symmetry.
-# R ⧠I = I ⧠R = R
+# R ⧠I = I ⧠R = R
# R â§ Ï = Ï â§ R = Ï
_and = curry ( _compaction_rule , AND , I , phi )
@@ -325,7 +325,7 @@ derivation.
We can save re-processing by remembering results we have already
computed. RE datastructures are immutable and the derv()
functions
are pure so this is fine.
-class Memo ( object ):
+class Memo ( object ):
def __init__ ( self , f ):
self . f = f
@@ -347,7 +347,7 @@ are pure so this is fine.
With âCompactionâ
This version uses the rules above to perform compaction. It keeps the
expressions from growing too large.
-def D_compaction ( symbol ):
+def D_compaction ( symbol ):
@Memo
def derv ( R ):
@@ -395,7 +395,7 @@ expressions from growing too large.
Letâs try it outâ¦
(FIXME: redo.)
-o , z = D_compaction ( '0' ), D_compaction ( '1' )
+o , z = D_compaction ( '0' ), D_compaction ( '1' )
REs = set ()
N = 5
names = list ( product ( * ( N * [( 0 , 1 )])))
@@ -500,8 +500,8 @@ machine transition table.
Says, âThree or more 1âs and not ending in 01 nor composed of all 1âs.â
-
-State Machine Graph
+
+omg.svg
Start at a
and follow the transition arrows according to their
@@ -555,18 +555,18 @@ a --1--> â1(a)
You can see the one-way nature of the g
state and the hij
âtrapâ
in the way that the .111.
on the left-hand side of the &
disappears once it has been matched.
-
from collections import defaultdict
+from collections import defaultdict
from pprint import pprint
from string import ascii_lowercase
-d0 , d1 = D_compaction ( '0' ), D_compaction ( '1' )
+d0 , d1 = D_compaction ( '0' ), D_compaction ( '1' )
explore()
-def explore ( re ):
+def explore ( re ):
# Don't have more than 26 states...
names = defaultdict ( iter ( ascii_lowercase ) . next )
@@ -592,7 +592,7 @@ disappears once it has been matched.
return table , accepting
-table , accepting = explore ( it )
+table , accepting = explore ( it )
table
@@ -618,7 +618,7 @@ disappears once it has been matched.
( 'j' , 1 ): 'h' }
-accepting
+
{ 'h' , 'i' }
@@ -629,7 +629,7 @@ disappears once it has been matched.
Generate Diagram
Once we have the FSM table and the set of accepting states we can
generate the diagram above.
-_template = ''' \
+_template = ''' \
digraph finite_state_machine {
rankdir=LR;
size="8,5"
@@ -653,7 +653,7 @@ generate the diagram above.
)
-print make_graph ( table , accepting )
+print make_graph ( table , accepting )
digraph finite_state_machine {
@@ -699,7 +699,7 @@ hard-code the information in the table into a little patch of branches.
Trampoline Function
Python has no GOTO statement but we can fake it with a âtrampolineâ
function.
-def trampoline ( input_ , jump_from , accepting ):
+def trampoline ( input_ , jump_from , accepting ):
I = iter ( input_ )
while True :
try :
@@ -714,7 +714,7 @@ function.
Stream Functions
Little helpers to process the iterator of our data (a âstreamâ of â1â
and â0â characters, not bits.)
-getch = lambda I : int ( next ( I ))
+getch = lambda I : int ( next ( I ))
def _1 ( I ):
@@ -735,7 +735,7 @@ and â0â characters, not bits.)
code. (You have to imagine that these are GOTO statements in C or
branches in assembly and that the state names are branch destination
labels.)
-a = lambda I : c if getch ( I ) else b
+a = lambda I : c if getch ( I ) else b
b = lambda I : _0 ( I ) or d
c = lambda I : e if getch ( I ) else b
d = lambda I : f if getch ( I ) else b
@@ -750,11 +750,11 @@ labels.)
Note that the implementations of h
and g
are identical ergo
h = g
and we could eliminate one in the code but h
is an
accepting state and g
isnât.
-def acceptable ( input_ ):
+def acceptable ( input_ ):
return trampoline ( input_ , a , { h , i })
-for n in range ( 2 ** 5 ):
+for n in range ( 2 ** 5 ):
s = bin ( n )[ 2 :]
print ' %05s ' % s , acceptable ( s )
@@ -878,6 +878,7 @@ derivative-with-respect-to-N of some other state/RE:
Treating Trees II: treestep
Using x
to Generate Values
Newtonâs method
+
Square Spiral Example Joy Code
Traversing Datastructures with Zippers
The Blissful Elegance of Typing Joy
Type Checking
diff --git a/docs/sphinx_docs/_build/html/notebooks/Generator_Programs.html b/docs/sphinx_docs/_build/html/notebooks/Generator_Programs.html
index 19aa59b..441434a 100644
--- a/docs/sphinx_docs/_build/html/notebooks/Generator_Programs.html
+++ b/docs/sphinx_docs/_build/html/notebooks/Generator_Programs.html
@@ -36,7 +36,7 @@
Using x
to Generate Values
Cf. jp-reprod.html
-from notebook_preamble import J , V , define
+from notebook_preamble import J , V , define
Consider the x
combinator:
@@ -76,7 +76,7 @@ function C
Letâs try it:
-V ( '[0 swap [dup ++] dip rest cons] x' )
+V ( '[0 swap [dup ++] dip rest cons] x' )
. [ 0 swap [ dup ++ ] dip rest cons ] x
@@ -95,7 +95,7 @@ function C
After one application of x
the quoted program contains 1
and
0
is below it on the stack.
-
J ( '[0 swap [dup ++] dip rest cons] x x x x x pop' )
+J ( '[0 swap [dup ++] dip rest cons] x x x x x pop' )
0 1 2 3 4
@@ -103,10 +103,10 @@ function C
direco
-define ( 'direco == dip rest cons' )
+define ( 'direco == dip rest cons' )
-V ( '[0 swap [dup ++] direco] x' )
+V ( '[0 swap [dup ++] direco] x' )
. [ 0 swap [ dup ++ ] direco ] x
@@ -147,17 +147,17 @@ our quoted program:
G == [ direco ] cons [ swap ] swoncat cons
-define ( 'G == [direco] cons [swap] swoncat cons' )
+define ( 'G == [direco] cons [swap] swoncat cons' )
Letâs try it out:
-J ( '0 [dup ++] G' )
+
-J ( '0 [dup ++] G x x x pop' )
+J ( '0 [dup ++] G x x x pop' )
0 1 2
@@ -165,7 +165,7 @@ our quoted program:
Powers of 2
-J ( '1 [dup 1 <<] G x x x x x x x x x pop' )
+J ( '1 [dup 1 <<] G x x x x x x x x x pop' )
1 2 4 8 16 32 64 128 256
@@ -176,7 +176,7 @@ our quoted program:
[x] times
If we have one of these quoted programs we can drive it using times
with the x
combinator.
-J ( '23 [dup ++] G 5 [x] times' )
+J ( '23 [dup ++] G 5 [x] times' )
23 24 25 26 27 [ 28 swap [ dup ++ ] direco ]
@@ -200,10 +200,10 @@ int:
And pick them off by masking with 3 (binary 11) and then shifting the
int right two bits.
-
define ( 'PE1.1 == dup [3 &] dip 2 >>' )
+define ( 'PE1.1 == dup [3 &] dip 2 >>' )
-V ( '14811 PE1.1' )
+
. 14811 PE1 . 1
@@ -220,14 +220,14 @@ int right two bits.
If we plug 14811
and [PE1.1]
into our generator formâ¦
-J ( '14811 [PE1.1] G' )
+
[ 14811 swap [ PE1 . 1 ] direco ]
â¦we get a generator that works for seven cycles before it reaches zero:
-J ( '[14811 swap [PE1.1] direco] 7 [x] times' )
+J ( '[14811 swap [PE1.1] direco] 7 [x] times' )
3 2 1 3 1 2 3 [ 0 swap [ PE1 . 1 ] direco ]
@@ -237,16 +237,16 @@ int right two bits.
Reset at Zero
We need a function that checks if the int has reached zero and resets it
if so.
-define ( 'PE1.1.check == dup [pop 14811] [] branch' )
+define ( 'PE1.1.check == dup [pop 14811] [] branch' )
-J ( '14811 [PE1.1.check PE1.1] G' )
+J ( '14811 [PE1.1.check PE1.1] G' )
[ 14811 swap [ PE1 . 1. check PE1 . 1 ] direco ]
-J ( '[14811 swap [PE1.1.check PE1.1] direco] 21 [x] times' )
+J ( '[14811 swap [PE1.1.check PE1.1] direco] 21 [x] times' )
3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 [ 0 swap [ PE1 . 1. check PE1 . 1 ] direco ]
@@ -262,20 +262,20 @@ say.)
In the PE1 problem we are asked to sum all the multiples of three and
five less than 1000. Itâs worked out that we need to use all seven
numbers sixty-six times and then four more.
-J ( '7 66 * 4 +' )
+
If we drive our generator 466 times and sum the stack we get 999.
-J ( '[14811 swap [PE1.1.check PE1.1] direco] 466 [x] times' )
+J ( '[14811 swap [PE1.1.check PE1.1] direco] 466 [x] times' )
3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 [ 57 swap [ PE1 . 1. check PE1 . 1 ] direco ]
-J ( '[14811 swap [PE1.1.check PE1.1] direco] 466 [x] times pop enstacken sum' )
+J ( '[14811 swap [PE1.1.check PE1.1] direco] 466 [x] times pop enstacken sum' )
999
@@ -285,11 +285,11 @@ numbers sixty-six times and then four more.
Project Euler Problem One
-define ( 'PE1.2 == + dup [+] dip' )
+define ( 'PE1.2 == + dup [+] dip' )
Now we can add PE1.2
to the quoted program given to G
.
-J ( '0 0 0 [PE1.1.check PE1.1] G 466 [x [PE1.2] dip] times popop' )
+J ( '0 0 0 [PE1.1.check PE1.1] G 466 [x [PE1.2] dip] times popop' )
233168
@@ -351,13 +351,13 @@ numbers sixty-six times and then four more.
fib_gen == [ 1 1 F ]
-define ( 'fib == + [popdd over] cons infra uncons' )
+define ( 'fib == + [popdd over] cons infra uncons' )
-define ( 'fib_gen == [1 1 fib]' )
+define ( 'fib_gen == [1 1 fib]' )
-J ( 'fib_gen 10 [x] times' )
+J ( 'fib_gen 10 [x] times' )
1 2 3 5 8 13 21 34 55 89 [ 144 89 fib ]
@@ -373,21 +373,21 @@ not exceed four million, find the sum of the even-valued terms.
Now that we have a generator for the Fibonacci sequence, we need a
function that adds a term in the sequence to a sum if it is even, and
pop
s it otherwise.
-define ( 'PE2.1 == dup 2 % [+] [pop] branch' )
+define ( 'PE2.1 == dup 2 % [+] [pop] branch' )
And a predicate function that detects when the terms in the series
âexceed four millionâ.
-define ( '>4M == 4000000 >' )
+define ( '>4M == 4000000 >' )
Now itâs straightforward to define PE2
as a recursive function that
generates terms in the Fibonacci sequence until they exceed four million
and sums the even ones.
-define ( 'PE2 == 0 fib_gen x [pop >4M] [popop] [[PE2.1] dip x] primrec' )
+define ( 'PE2 == 0 fib_gen x [pop >4M] [popop] [[PE2.1] dip x] primrec' )
-J ( 'PE2' )
+
4613732
@@ -418,23 +418,23 @@ and sums the even ones.
Every third term is even.
-J ( '[1 0 fib] x x x' ) # To start the sequence with 1 1 2 3 instead of 1 2 3.
+J ( '[1 0 fib] x x x' ) # To start the sequence with 1 1 2 3 instead of 1 2 3.
Drive the generator three times and popop
the two odd terms.
-J ( '[1 0 fib] x x x [popop] dipd' )
+J ( '[1 0 fib] x x x [popop] dipd' )
-define ( 'PE2.2 == x x x [popop] dipd' )
+define ( 'PE2.2 == x x x [popop] dipd' )
-J ( '[1 0 fib] 10 [PE2.2] times' )
+J ( '[1 0 fib] 10 [PE2.2] times' )
2 8 34 144 610 2584 10946 46368 196418 832040 [ 1346269 832040 fib ]
@@ -442,7 +442,7 @@ and sums the even ones.
Replace x
with our new driver function PE2.2
and start our
fib
generator at 1 0
.
-
J ( '0 [1 0 fib] PE2.2 [pop >4M] [popop] [[PE2.1] dip PE2.2] primrec' )
+J ( '0 [1 0 fib] PE2.2 [pop >4M] [popop] [[PE2.1] dip PE2.2] primrec' )
4613732
@@ -457,10 +457,10 @@ modifications to the default
An Interesting Variation
-