Update Square_Spiral notebook to use Joy kernel

https://todo.sr.ht/~sforman/thun-der/19
This commit is contained in:
Simon Forman 2021-11-27 17:04:15 -08:00
parent dafdb9d620
commit d420f572df
4 changed files with 16962 additions and 13650 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,3 @@
```python
from notebook_preamble import J, V, define
```
# Square Spiral Example Joy Code # Square Spiral Example Joy Code
@ -65,28 +61,177 @@ with `<=`:
[abs] ii <= [abs] ii <=
```Joy
[_p [abs] ii <=] inscribe
```
```Joy
clear 23 -18
```
23 -18
```Joy
[_p] trace
```
23 -18 • _p
23 -18 • [abs] ii <=
23 -18 [abs] • ii <=
23 • abs -18 abs <=
23 • -18 abs <=
23 -18 • abs <=
23 18 • <=
false •
false
```Joy
clear
```
### Short-Circuiting Boolean Combinators
I've defined two short-circuiting Boolean combinators `&&` and `||` that I've defined two short-circuiting Boolean combinators `&&` and `||` that
each accept two quoted predicate programs, run the first, and each accept two quoted predicate programs, run the first, and
conditionally run the second only if required (to compute the final conditionally run the second only if required (to compute the final
Boolean value). They run their predicate arguments `nullary`. Boolean value). They run their predicate arguments `nullary`.
```python ```Joy
define('&& [nullary] cons [nullary [0]] dip branch') [&& [nullary] cons [nullary [false]] dip branch] inscribe
define('|| [nullary] cons [nullary] dip [1] branch') [|| [nullary] cons [nullary] dip [true] branch] inscribe
``` ```
```Joy
clear
[true] [false] &&
```
false
```Joy
clear
[false] [true] &&
```
false
```Joy
clear
[true] [false] ||
```
true
```Joy
clear
[false] [true] ||
```
true
```Joy
clear
```
### Translating the Conditionals
Given those, we can define `x != y || x >= 0` as: Given those, we can define `x != y || x >= 0` as:
[<>] [pop 0 >=] || _a == [!=] [pop 0 >=] ||
```Joy
[_a [!=] [pop 0 >=] ||] inscribe
```
And `(abs(x) <= abs(y) && (x != y || x >= 0))` as: And `(abs(x) <= abs(y) && (x != y || x >= 0))` as:
[[abs] ii <=] [[<>] [pop 0 >=] ||] && _b == [_p] [_a] &&
```Joy
[_b [_p] [_a] &&] inscribe
```
It's a little rough, but, as I say, with a little familiarity it becomes It's a little rough, but, as I say, with a little familiarity it becomes
legible. legible.
```Joy
clear 23 -18
```
23 -18
```Joy
[_b] trace
```
23 -18 • _b
23 -18 • [_p] [_a] &&
23 -18 [_p] • [_a] &&
23 -18 [_p] [_a] • &&
23 -18 [_p] [_a] • [nullary] cons [nullary [false]] dip branch
23 -18 [_p] [_a] [nullary] • cons [nullary [false]] dip branch
23 -18 [_p] [[_a] nullary] • [nullary [false]] dip branch
23 -18 [_p] [[_a] nullary] [nullary [false]] • dip branch
23 -18 [_p] • nullary [false] [[_a] nullary] branch
23 -18 [_p] • [stack] dinfrirst [false] [[_a] nullary] branch
23 -18 [_p] [stack] • dinfrirst [false] [[_a] nullary] branch
23 -18 [_p] [stack] • dip infrst [false] [[_a] nullary] branch
23 -18 • stack [_p] infrst [false] [[_a] nullary] branch
23 -18 [-18 23] • [_p] infrst [false] [[_a] nullary] branch
23 -18 [-18 23] [_p] • infrst [false] [[_a] nullary] branch
23 -18 [-18 23] [_p] • infra first [false] [[_a] nullary] branch
23 -18 • _p [-18 23] swaack first [false] [[_a] nullary] branch
23 -18 • [abs] ii <= [-18 23] swaack first [false] [[_a] nullary] branch
23 -18 [abs] • ii <= [-18 23] swaack first [false] [[_a] nullary] branch
23 • abs -18 abs <= [-18 23] swaack first [false] [[_a] nullary] branch
23 • -18 abs <= [-18 23] swaack first [false] [[_a] nullary] branch
23 -18 • abs <= [-18 23] swaack first [false] [[_a] nullary] branch
23 18 • <= [-18 23] swaack first [false] [[_a] nullary] branch
false • [-18 23] swaack first [false] [[_a] nullary] branch
false [-18 23] • swaack first [false] [[_a] nullary] branch
23 -18 [false] • first [false] [[_a] nullary] branch
23 -18 false • [false] [[_a] nullary] branch
23 -18 false [false] • [[_a] nullary] branch
23 -18 false [false] [[_a] nullary] • branch
23 -18 • false
23 -18 false •
23 -18 false
```Joy
clear
```
### The Increment / Decrement Branches ### The Increment / Decrement Branches
Turning to the branches of the main `if` statement: Turning to the branches of the main `if` statement:
@ -113,13 +258,6 @@ Similar logic applies to the other branch:
[pop 0 >=] [--] [++] ifte [pop 0 >=] [--] [++] ifte
### "Not Negative"
```python
define('!- 0 >=')
```
## Putting the Pieces Together ## Putting the Pieces Together
We can assemble the three functions we just defined in quotes and give We can assemble the three functions we just defined in quotes and give
@ -131,6 +269,20 @@ the symmetry of the two branches, we have:
[[pop !-] [--] [++] ifte ] [[pop !-] [--] [++] ifte ]
ifte ifte
```Joy
[spiral_next
[_b]
[[ !-] [[++]] [[--]] ifte dip]
[[pop !-] [--] [++] ifte ]
ifte
] inscribe
```
As I was writing this up I realized that, since the `&&` combinator 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 doesn't consume the stack (below its quoted args), I can unquote the
predicate, swap the branches, and use the `branch` combinator instead of predicate, swap the branches, and use the `branch` combinator instead of
@ -141,45 +293,120 @@ predicate, swap the branches, and use the `branch` combinator instead of
[[ !-] [[++]] [[--]] ifte dip] [[ !-] [[++]] [[--]] ifte dip]
branch branch
```python
define('spiral_next [[[abs] ii <=] [[<>] [pop !-] ||] &&] [[!-] [[++]] [[--]] ifte dip] [[pop !-] [--] [++] ifte] ifte')
```
Let's try it out: Let's try it out:
```python ```Joy
J('0 0 spiral_next') clear 0 0
```
0 0
```Joy
spiral_next
``` ```
1 0 1 0
```Joy
```python spiral_next
J('1 0 spiral_next')
``` ```
1 -1 1 -1
```Joy
```python spiral_next
J('1 -1 spiral_next')
``` ```
0 -1 0 -1
```Joy
```python spiral_next
J('0 -1 spiral_next')
``` ```
-1 -1 -1 -1
```Joy
spiral_next
```
-1 0
```Joy
spiral_next
```
-1 1
```Joy
spiral_next
```
0 1
```Joy
spiral_next
```
1 1
```Joy
spiral_next
```
2 1
```Joy
spiral_next
```
2 0
```Joy
spiral_next
```
2 -1
```Joy
spiral_next
```
2 -2
```Joy
spiral_next
```
1 -2
```Joy
spiral_next
```
0 -2
```Joy
spiral_next
```
-1 -2
## Turning it into a Generator with `x` ## Turning it into a Generator with `x`
It can be used with the x combinator to make a kind of generator for It can be used with the x combinator to make a kind of generator for
@ -188,7 +415,7 @@ spiral square coordinates.
We can use `codireco` to make a generator We can use `codireco` to make a generator
codireco ::= cons dip rest cons codireco == cons dip rest cons
It will look like this: It will look like this:
@ -196,19 +423,37 @@ It will look like this:
Here's a trace of how it works: Here's a trace of how it works:
[0 [dup ++] codireco] . x
[0 [dup ++] codireco] . 0 [dup ++] codireco ```Joy
[0 [dup ++] codireco] 0 . [dup ++] codireco clear
[0 [dup ++] codireco] 0 [dup ++] . codireco
[0 [dup ++] codireco] 0 [dup ++] . cons dip rest cons [0 [dup ++] codireco] [x] trace
[0 [dup ++] codireco] [0 dup ++] . dip rest cons ```
. 0 dup ++ [0 [dup ++] codireco] rest cons
0 . dup ++ [0 [dup ++] codireco] rest cons [0 [dup ++] codireco] • x
0 0 . ++ [0 [dup ++] codireco] rest cons [0 [dup ++] codireco] • 0 [dup ++] codireco
0 1 . [0 [dup ++] codireco] rest cons [0 [dup ++] codireco] 0 • [dup ++] codireco
0 1 [0 [dup ++] codireco] . rest cons [0 [dup ++] codireco] 0 [dup ++] • codireco
0 1 [[dup ++] codireco] . cons [0 [dup ++] codireco] 0 [dup ++] • codi reco
0 [1 [dup ++] codireco] . [0 [dup ++] codireco] 0 [dup ++] • cons dip reco
[0 [dup ++] codireco] [0 dup ++] • dip reco
• 0 dup ++ [0 [dup ++] codireco] reco
0 • dup ++ [0 [dup ++] codireco] reco
0 0 • ++ [0 [dup ++] codireco] reco
0 1 • [0 [dup ++] codireco] reco
0 1 [0 [dup ++] codireco] • reco
0 1 [0 [dup ++] codireco] • rest cons
0 1 [[dup ++] codireco] • cons
0 [1 [dup ++] codireco] •
0 [1 [dup ++] codireco]
```Joy
clear
```
But first we have to change the `spiral_next` function to work on a 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. quoted pair of integers, and leave a copy of the pair on the stack.
@ -225,13 +470,12 @@ to:
[x' y'] [x' y']
```python ```Joy
J('[0 0] [spiral_next] infra') [0 0] [spiral_next] infra
``` ```
[0 1] [0 1]
So our generator is: So our generator is:
[[x y] [dup [spiral_next] infra] codireco] [[x y] [dup [spiral_next] infra] codireco]
@ -247,30 +491,49 @@ out of the value and stepper function:
---------------------------------------------------- ----------------------------------------------------
[[0 0] [dup [spiral_next] infra] codireco] [[0 0] [dup [spiral_next] infra] codireco]
```Joy
clear
```
Here it is in action: Here it is in action:
```python ```Joy
J('[0 0] [dup [spiral_next] infra] make_generator x x x x pop') [0 0] [dup [spiral_next] infra] make_generator x x x x pop
``` ```
[0 0] [0 1] [-1 1] [-1 0] [0 0] [0 1] [-1 1] [-1 0]
Four `x` combinators, four pairs of coordinates. Four `x` combinators, four pairs of coordinates.
Or you can leave out `dup` and let the value stay in the generator until you want it:
```Joy
clear
[0 0] [[spiral_next] infra] make_generator 50 [x] times first
```
[2 4]
## Conclusion ## Conclusion
So that's an example of Joy code. It's a straightforward translation of 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 the original. It's a little long for a single definition, you might
break it up like so: break it up like so:
_spn_P ::= [[abs] ii <=] [[<>] [pop !-] ||] && _spn_Pa == [abs] ii <=
_spn_Pb == [!=] [pop 0 >=] ||
_spn_P == [_spn_Pa] [_spn_Pb] &&
_spn_T == [ !-] [[++]] [[--]] ifte dip
_spn_E == [pop !-] [--] [++] ifte
_spn_T ::= [ !-] [[++]] [[--]] ifte dip spiral_next == _spn_P [_spn_E] [_spn_T] branch
_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 This way it's easy to see that the function is a branch with two
quasi-symmetrical paths. quasi-symmetrical paths.
@ -280,84 +543,3 @@ 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 using the `x` combinator on the generator (which is just a quoted
expression containing a copy of the current pair and the "stepper expression containing a copy of the current pair and the "stepper
function" to generate the next pair from that.) 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 .

View File

@ -1,7 +1,3 @@
.. code:: ipython3
from notebook_preamble import J, V, define
Square Spiral Example Joy Code Square Spiral Example Joy Code
============================== ==============================
@ -9,21 +5,21 @@ Here is the example of Joy code from the ``README`` file:
:: ::
[[[abs]ii <=][[<>][pop !-]||]&&][[!-][[++]][[--]]ifte dip][[pop !-][--][++]ifte]ifte [[[abs]ii <=][[<>][pop !-]||]&&][[!-][[++]][[--]]ifte dip][[pop !-][--][++]ifte]ifte
It might seem unreadable but with a little familiarity it becomes just It might seem unreadable but with a little familiarity it becomes just
as legible as any other notation. Some layout helps: as legible as any other notation. Some layout helps:
:: ::
[ [[abs] ii <=] [ [[abs] ii <=]
[ [
[<>] [pop !-] || [<>] [pop !-] ||
] && ] &&
] ]
[[ !-] [[++]] [[--]] ifte dip] [[ !-] [[++]] [[--]] ifte dip]
[[pop !-] [--] [++] ifte ] [[pop !-] [--] [++] ifte ]
ifte ifte
This function accepts two integers on the stack and increments or 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 decrements one of them such that the new pair of numbers is the next
@ -33,34 +29,34 @@ Ulam Spiral).
Original Form Original Form
------------- -------------
It's adapted from `the original code on Its adapted from `the original code on
StackOverflow <https://stackoverflow.com/questions/398299/looping-in-a-spiral/31864777#31864777>`__: 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 If all youre trying to do is generate the first N points in the
spiral (without the original problem's constraint of masking to an N spiral (without the original problems constraint of masking to an N
x M region), the code becomes very simple: x M region), the code becomes very simple:
:: ::
void spiral(const int N) void spiral(const int N)
{ {
int x = 0; int x = 0;
int y = 0; int y = 0;
for(int i = 0; i < N; ++i) for(int i = 0; i < N; ++i)
{ {
cout << x << '\t' << y << '\n'; cout << x << '\t' << y << '\n';
if(abs(x) <= abs(y) && (x != y || x >= 0)) if(abs(x) <= abs(y) && (x != y || x >= 0))
x += ((y >= 0) ? 1 : -1); x += ((y >= 0) ? 1 : -1);
else else
y += ((x >= 0) ? -1 : 1); y += ((x >= 0) ? -1 : 1);
} }
} }
Translation to Joy Translation to Joy
------------------ ------------------
I'm going to make a function that take two ints (``x`` and ``y``) and Im 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 generates the next pair, well turn it into a generator later using the
``x`` combinator. ``x`` combinator.
First Boolean Predicate First Boolean Predicate
@ -71,33 +67,215 @@ to apply ``abs`` to both values and then compare them with ``<=``:
:: ::
[abs] ii <= [abs] ii <=
I've defined two short-circuiting Boolean combinators ``&&`` and ``||`` .. code:: Joy
[_p [abs] ii <=] inscribe
.. parsed-literal::
.. code:: Joy
clear 23 -18
.. parsed-literal::
23 -18
.. code:: Joy
[_p] trace
.. parsed-literal::
23 -18 • _p
23 -18 • [abs] ii <=
23 -18 [abs] • ii <=
23 • abs -18 abs <=
23 • -18 abs <=
23 -18 • abs <=
23 18 • <=
false •
false
.. code:: Joy
clear
.. parsed-literal::
Short-Circuiting Boolean Combinators
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Ive defined two short-circuiting Boolean combinators ``&&`` and ``||``
that each accept two quoted predicate programs, run the first, and that each accept two quoted predicate programs, run the first, and
conditionally run the second only if required (to compute the final conditionally run the second only if required (to compute the final
Boolean value). They run their predicate arguments ``nullary``. Boolean value). They run their predicate arguments ``nullary``.
.. code:: ipython3 .. code:: Joy
define('&& [nullary] cons [nullary [0]] dip branch') [&& [nullary] cons [nullary [false]] dip branch] inscribe
define('|| [nullary] cons [nullary] dip [1] branch') [|| [nullary] cons [nullary] dip [true] branch] inscribe
.. parsed-literal::
.. code:: Joy
clear
[true] [false] &&
.. parsed-literal::
false
.. code:: Joy
clear
[false] [true] &&
.. parsed-literal::
false
.. code:: Joy
clear
[true] [false] ||
.. parsed-literal::
true
.. code:: Joy
clear
[false] [true] ||
.. parsed-literal::
true
.. code:: Joy
clear
.. parsed-literal::
Translating the Conditionals
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Given those, we can define ``x != y || x >= 0`` as: Given those, we can define ``x != y || x >= 0`` as:
:: ::
[<>] [pop 0 >=] || _a == [!=] [pop 0 >=] ||
.. code:: Joy
[_a [!=] [pop 0 >=] ||] inscribe
.. parsed-literal::
And ``(abs(x) <= abs(y) && (x != y || x >= 0))`` as: And ``(abs(x) <= abs(y) && (x != y || x >= 0))`` as:
:: ::
[[abs] ii <=] [[<>] [pop 0 >=] ||] && _b == [_p] [_a] &&
It's a little rough, but, as I say, with a little familiarity it becomes .. code:: Joy
[_b [_p] [_a] &&] inscribe
.. parsed-literal::
Its a little rough, but, as I say, with a little familiarity it becomes
legible. legible.
.. code:: Joy
clear 23 -18
.. parsed-literal::
23 -18
.. code:: Joy
[_b] trace
.. parsed-literal::
23 -18 • _b
23 -18 • [_p] [_a] &&
23 -18 [_p] • [_a] &&
23 -18 [_p] [_a] • &&
23 -18 [_p] [_a] • [nullary] cons [nullary [false]] dip branch
23 -18 [_p] [_a] [nullary] • cons [nullary [false]] dip branch
23 -18 [_p] [[_a] nullary] • [nullary [false]] dip branch
23 -18 [_p] [[_a] nullary] [nullary [false]] • dip branch
23 -18 [_p] • nullary [false] [[_a] nullary] branch
23 -18 [_p] • [stack] dinfrirst [false] [[_a] nullary] branch
23 -18 [_p] [stack] • dinfrirst [false] [[_a] nullary] branch
23 -18 [_p] [stack] • dip infrst [false] [[_a] nullary] branch
23 -18 • stack [_p] infrst [false] [[_a] nullary] branch
23 -18 [-18 23] • [_p] infrst [false] [[_a] nullary] branch
23 -18 [-18 23] [_p] • infrst [false] [[_a] nullary] branch
23 -18 [-18 23] [_p] • infra first [false] [[_a] nullary] branch
23 -18 • _p [-18 23] swaack first [false] [[_a] nullary] branch
23 -18 • [abs] ii <= [-18 23] swaack first [false] [[_a] nullary] branch
23 -18 [abs] • ii <= [-18 23] swaack first [false] [[_a] nullary] branch
23 • abs -18 abs <= [-18 23] swaack first [false] [[_a] nullary] branch
23 • -18 abs <= [-18 23] swaack first [false] [[_a] nullary] branch
23 -18 • abs <= [-18 23] swaack first [false] [[_a] nullary] branch
23 18 • <= [-18 23] swaack first [false] [[_a] nullary] branch
false • [-18 23] swaack first [false] [[_a] nullary] branch
false [-18 23] • swaack first [false] [[_a] nullary] branch
23 -18 [false] • first [false] [[_a] nullary] branch
23 -18 false • [false] [[_a] nullary] branch
23 -18 false [false] • [[_a] nullary] branch
23 -18 false [false] [[_a] nullary] • branch
23 -18 • false
23 -18 false •
23 -18 false
.. code:: Joy
clear
.. parsed-literal::
The Increment / Decrement Branches The Increment / Decrement Branches
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -105,42 +283,35 @@ Turning to the branches of the main ``if`` statement:
:: ::
x += ((y >= 0) ? 1 : -1); x += ((y >= 0) ? 1 : -1);
Rewrite as a hybrid (pseudo-code) ``ifte`` expression: Rewrite as a hybrid (pseudo-code) ``ifte`` expression:
:: ::
[y >= 0] [x += 1] [X -= 1] ifte [y >= 0] [x += 1] [X -= 1] ifte
Change each C phrase to Joy code: Change each C phrase to Joy code:
:: ::
[0 >=] [[++] dip] [[--] dip] ifte [0 >=] [[++] dip] [[--] dip] ifte
Factor out the dip from each branch: Factor out the dip from each branch:
:: ::
[0 >=] [[++]] [[--]] ifte dip [0 >=] [[++]] [[--]] ifte dip
Similar logic applies to the other branch: Similar logic applies to the other branch:
:: ::
y += ((x >= 0) ? -1 : 1); y += ((x >= 0) ? -1 : 1);
[x >= 0] [y -= 1] [y += 1] ifte [x >= 0] [y -= 1] [y += 1] ifte
[pop 0 >=] [--] [++] ifte [pop 0 >=] [--] [++] ifte
"Not Negative"
~~~~~~~~~~~~~~
.. code:: ipython3
define('!- 0 >=')
Putting the Pieces Together Putting the Pieces Together
--------------------------- ---------------------------
@ -151,68 +322,184 @@ the symmetry of the two branches, we have:
:: ::
[[[abs] ii <=] [[<>] [pop !-] ||] &&] [[[abs] ii <=] [[<>] [pop !-] ||] &&]
[[ !-] [[++]] [[--]] ifte dip]
[[pop !-] [--] [++] ifte ]
ifte
.. code:: Joy
[spiral_next
[_b]
[[ !-] [[++]] [[--]] ifte dip] [[ !-] [[++]] [[--]] ifte dip]
[[pop !-] [--] [++] ifte ] [[pop !-] [--] [++] ifte ]
ifte ifte
] inscribe
.. parsed-literal::
As I was writing this up I realized that, since the ``&&`` combinator 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 doesnt consume the stack (below its quoted args), I can unquote the
predicate, swap the branches, and use the ``branch`` combinator instead predicate, swap the branches, and use the ``branch`` combinator instead
of ``ifte``: of ``ifte``:
:: ::
[[abs] ii <=] [[<>] [pop !-] ||] && [[abs] ii <=] [[<>] [pop !-] ||] &&
[[pop !-] [--] [++] ifte ] [[pop !-] [--] [++] ifte ]
[[ !-] [[++]] [[--]] ifte dip] [[ !-] [[++]] [[--]] ifte dip]
branch branch
.. code:: ipython3 Lets try it out:
define('spiral_next [[[abs] ii <=] [[<>] [pop !-] ||] &&] [[!-] [[++]] [[--]] ifte dip] [[pop !-] [--] [++] ifte] ifte') .. code:: Joy
Let's try it out: clear 0 0
.. code:: ipython3
J('0 0 spiral_next') .. parsed-literal::
0 0
.. code:: Joy
spiral_next
.. parsed-literal:: .. parsed-literal::
1 0 1 0
.. code:: Joy
.. code:: ipython3 spiral_next
J('1 0 spiral_next')
.. parsed-literal:: .. parsed-literal::
1 -1 1 -1
.. code:: Joy
.. code:: ipython3 spiral_next
J('1 -1 spiral_next')
.. parsed-literal:: .. parsed-literal::
0 -1 0 -1
.. code:: Joy
.. code:: ipython3 spiral_next
J('0 -1 spiral_next')
.. parsed-literal:: .. parsed-literal::
-1 -1 -1 -1
.. code:: Joy
spiral_next
.. parsed-literal::
-1 0
.. code:: Joy
spiral_next
.. parsed-literal::
-1 1
.. code:: Joy
spiral_next
.. parsed-literal::
0 1
.. code:: Joy
spiral_next
.. parsed-literal::
1 1
.. code:: Joy
spiral_next
.. parsed-literal::
2 1
.. code:: Joy
spiral_next
.. parsed-literal::
2 0
.. code:: Joy
spiral_next
.. parsed-literal::
2 -1
.. code:: Joy
spiral_next
.. parsed-literal::
2 -2
.. code:: Joy
spiral_next
.. parsed-literal::
1 -2
.. code:: Joy
spiral_next
.. parsed-literal::
0 -2
.. code:: Joy
spiral_next
.. parsed-literal::
-1 -2
Turning it into a Generator with ``x`` Turning it into a Generator with ``x``
-------------------------------------- --------------------------------------
@ -224,31 +511,51 @@ We can use ``codireco`` to make a generator
:: ::
codireco ::= cons dip rest cons codireco == cons dip rest cons
It will look like this: It will look like this:
:: ::
[value [F] codireco] [value [F] codireco]
Here's a trace of how it works: Heres a trace of how it works:
:: .. code:: Joy
[0 [dup ++] codireco] . x clear
[0 [dup ++] codireco] . 0 [dup ++] codireco
[0 [dup ++] codireco] 0 . [dup ++] codireco [0 [dup ++] codireco] [x] trace
[0 [dup ++] codireco] 0 [dup ++] . codireco
[0 [dup ++] codireco] 0 [dup ++] . cons dip rest cons
[0 [dup ++] codireco] [0 dup ++] . dip rest cons .. parsed-literal::
. 0 dup ++ [0 [dup ++] codireco] rest cons
0 . dup ++ [0 [dup ++] codireco] rest cons [0 [dup ++] codireco] • x
0 0 . ++ [0 [dup ++] codireco] rest cons [0 [dup ++] codireco] • 0 [dup ++] codireco
0 1 . [0 [dup ++] codireco] rest cons [0 [dup ++] codireco] 0 • [dup ++] codireco
0 1 [0 [dup ++] codireco] . rest cons [0 [dup ++] codireco] 0 [dup ++] • codireco
0 1 [[dup ++] codireco] . cons [0 [dup ++] codireco] 0 [dup ++] • codi reco
0 [1 [dup ++] codireco] . [0 [dup ++] codireco] 0 [dup ++] • cons dip reco
[0 [dup ++] codireco] [0 dup ++] • dip reco
• 0 dup ++ [0 [dup ++] codireco] reco
0 • dup ++ [0 [dup ++] codireco] reco
0 0 • ++ [0 [dup ++] codireco] reco
0 1 • [0 [dup ++] codireco] reco
0 1 [0 [dup ++] codireco] • reco
0 1 [0 [dup ++] codireco] • rest cons
0 1 [[dup ++] codireco] • cons
0 [1 [dup ++] codireco] •
0 [1 [dup ++] codireco]
.. code:: Joy
clear
.. parsed-literal::
But first we have to change the ``spiral_next`` function to work on a 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. quoted pair of integers, and leave a copy of the pair on the stack.
@ -256,166 +563,107 @@ From:
:: ::
y x spiral_next y x spiral_next
--------------------- ---------------------
y' x' y' x'
to: to:
:: ::
[x y] [spiral_next] infra [x y] [spiral_next] infra
------------------------------- -------------------------------
[x' y'] [x' y']
.. code:: ipython3 .. code:: Joy
J('[0 0] [spiral_next] infra') [0 0] [spiral_next] infra
.. parsed-literal:: .. parsed-literal::
[0 1] [0 1]
So our generator is: So our generator is:
:: ::
[[x y] [dup [spiral_next] infra] codireco] [[x y] [dup [spiral_next] infra] codireco]
Or rather: Or rather:
:: ::
[[0 0] [dup [spiral_next] infra] codireco] [[0 0] [dup [spiral_next] infra] codireco]
There is a function ``make_generator`` that will build the generator for There is a function ``make_generator`` that will build the generator for
us out of the value and stepper function: us out of the value and stepper function:
:: ::
[0 0] [dup [spiral_next] infra] make_generator [0 0] [dup [spiral_next] infra] make_generator
---------------------------------------------------- ----------------------------------------------------
[[0 0] [dup [spiral_next] infra] codireco] [[0 0] [dup [spiral_next] infra] codireco]
.. code:: Joy
clear
.. parsed-literal::
Here it is in action: Here it is in action:
.. code:: ipython3 .. code:: Joy
J('[0 0] [dup [spiral_next] infra] make_generator x x x x pop') [0 0] [dup [spiral_next] infra] make_generator x x x x pop
.. parsed-literal:: .. parsed-literal::
[0 0] [0 1] [-1 1] [-1 0] [0 0] [0 1] [-1 1] [-1 0]
Four ``x`` combinators, four pairs of coordinates. Four ``x`` combinators, four pairs of coordinates.
Or you can leave out ``dup`` and let the value stay in the generator
until you want it:
.. code:: Joy
clear
[0 0] [[spiral_next] infra] make_generator 50 [x] times first
.. parsed-literal::
[2 4]
Conclusion Conclusion
---------- ----------
So that's an example of Joy code. It's a straightforward translation of So thats an example of Joy code. Its a straightforward translation of
the original. It's a little long for a single definition, you might the original. Its a little long for a single definition, you might
break it up like so: break it up like so:
:: ::
_spn_P ::= [[abs] ii <=] [[<>] [pop !-] ||] && _spn_Pa == [abs] ii <=
_spn_Pb == [!=] [pop 0 >=] ||
_spn_P == [_spn_Pa] [_spn_Pb] &&
_spn_T ::= [ !-] [[++]] [[--]] ifte dip _spn_T == [ !-] [[++]] [[--]] ifte dip
_spn_E ::= [pop !-] [--] [++] ifte _spn_E == [pop !-] [--] [++] ifte
spiral_next ::= _spn_P [_spn_E] [_spn_T] branch spiral_next == _spn_P [_spn_E] [_spn_T] branch
This way it's easy to see that the function is a branch with two This way its easy to see that the function is a branch with two
quasi-symmetrical paths. quasi-symmetrical paths.
We then used this function to make a simple generator of coordinate 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 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 using the ``x`` combinator on the generator (which is just a quoted
expression containing a copy of the current pair and the "stepper expression containing a copy of the current pair and the “stepper
function" to generate the next pair from that.) 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 .