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
@ -65,28 +61,177 @@ with `<=`:
[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
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')
```Joy
[&& [nullary] cons [nullary [false]] dip branch] inscribe
[|| [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:
[<>] [pop 0 >=] ||
_a == [!=] [pop 0 >=] ||
```Joy
[_a [!=] [pop 0 >=] ||] inscribe
```
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
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
Turning to the branches of the main `if` statement:
@ -113,13 +258,6 @@ Similar logic applies to the other branch:
[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
@ -131,6 +269,20 @@ the symmetry of the two branches, we have:
[[pop !-] [--] [++] ifte ]
ifte
```Joy
[spiral_next
[_b]
[[ !-] [[++]] [[--]] ifte dip]
[[pop !-] [--] [++] ifte ]
ifte
] inscribe
```
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
@ -141,45 +293,120 @@ predicate, swap the branches, and use the `branch` combinator instead of
[[ !-] [[++]] [[--]] 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')
```Joy
clear 0 0
```
0 0
```Joy
spiral_next
```
1 0
```python
J('1 0 spiral_next')
```Joy
spiral_next
```
1 -1
```python
J('1 -1 spiral_next')
```Joy
spiral_next
```
0 -1
```python
J('0 -1 spiral_next')
```Joy
spiral_next
```
-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`
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
codireco ::= cons dip rest cons
codireco == cons dip rest cons
It will look like this:
@ -196,19 +423,37 @@ It will look like this:
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] .
```Joy
clear
[0 [dup ++] codireco] [x] trace
```
[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 ++] • codi reco
[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
quoted pair of integers, and leave a copy of the pair on the stack.
@ -225,13 +470,12 @@ to:
[x' y']
```python
J('[0 0] [spiral_next] infra')
```Joy
[0 0] [spiral_next] infra
```
[0 1]
So our generator is:
[[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]
```Joy
clear
```
Here it is in action:
```python
J('[0 0] [dup [spiral_next] infra] make_generator x x x x pop')
```Joy
[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.
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
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_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
_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
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
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 .

View File

@ -1,7 +1,3 @@
.. code:: ipython3
from notebook_preamble import J, V, define
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
as legible as any other notation. Some layout helps:
::
[ [[abs] ii <=]
[
[<>] [pop !-] ||
] &&
]
[[ !-] [[++]] [[--]] ifte dip]
[[pop !-] [--] [++] ifte ]
ifte
[ [[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
@ -33,34 +29,34 @@ Ulam Spiral).
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>`__:
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:
If all youre trying to do is generate the first N points in the
spiral (without the original problems 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);
}
}
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
Im going to make a function that take two ints (``x`` and ``y``) and
generates the next pair, well turn it into a generator later using the
``x`` combinator.
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
conditionally run the second only if required (to compute the final
Boolean value). They run their predicate arguments ``nullary``.
.. code:: ipython3
.. code:: Joy
define('&& [nullary] cons [nullary [0]] dip branch')
define('|| [nullary] cons [nullary] dip [1] branch')
[&& [nullary] cons [nullary [false]] dip branch] inscribe
[|| [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:
::
[<>] [pop 0 >=] ||
_a == [!=] [pop 0 >=] ||
.. code:: Joy
[_a [!=] [pop 0 >=] ||] inscribe
.. parsed-literal::
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.
.. 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
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -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:
::
[y >= 0] [x += 1] [X -= 1] ifte
[y >= 0] [x += 1] [X -= 1] ifte
Change each C phrase to Joy code:
::
[0 >=] [[++] dip] [[--] dip] ifte
[0 >=] [[++] dip] [[--] dip] ifte
Factor out the dip from each branch:
::
[0 >=] [[++]] [[--]] ifte dip
[0 >=] [[++]] [[--]] ifte dip
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
"Not Negative"
~~~~~~~~~~~~~~
.. code:: ipython3
define('!- 0 >=')
[pop 0 >=] [--] [++] ifte
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]
[[pop !-] [--] [++] ifte ]
ifte
] inscribe
.. parsed-literal::
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
of ``ifte``:
::
[[abs] ii <=] [[<>] [pop !-] ||] &&
[[pop !-] [--] [++] ifte ]
[[ !-] [[++]] [[--]] ifte dip]
branch
[[abs] ii <=] [[<>] [pop !-] ||] &&
[[pop !-] [--] [++] ifte ]
[[ !-] [[++]] [[--]] ifte dip]
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::
1 0
.. code:: Joy
.. code:: ipython3
J('1 0 spiral_next')
spiral_next
.. parsed-literal::
1 -1
.. code:: Joy
.. code:: ipython3
J('1 -1 spiral_next')
spiral_next
.. parsed-literal::
0 -1
.. code:: Joy
.. code:: ipython3
J('0 -1 spiral_next')
spiral_next
.. parsed-literal::
-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``
--------------------------------------
@ -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:
::
[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
[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] .
clear
[0 [dup ++] codireco] [x] trace
.. parsed-literal::
[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 ++] • codi reco
[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
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'
y x spiral_next
---------------------
y' x'
to:
::
[x y] [spiral_next] infra
-------------------------------
[x' y']
[x y] [spiral_next] infra
-------------------------------
[x' y']
.. code:: ipython3
.. code:: Joy
J('[0 0] [spiral_next] infra')
[0 0] [spiral_next] infra
.. parsed-literal::
[0 1]
So our generator is:
::
[[x y] [dup [spiral_next] infra] codireco]
[[x y] [dup [spiral_next] infra] codireco]
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
us out of the value and stepper function:
::
[0 0] [dup [spiral_next] infra] make_generator
----------------------------------------------------
[[0 0] [dup [spiral_next] infra] codireco]
[0 0] [dup [spiral_next] infra] make_generator
----------------------------------------------------
[[0 0] [dup [spiral_next] infra] codireco]
.. code:: Joy
clear
.. parsed-literal::
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::
[0 0] [0 1] [-1 1] [-1 0]
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
----------
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
So thats an example of Joy code. Its a straightforward translation of
the original. Its a little long for a single definition, you might
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
_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.
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 .
expression containing a copy of the current pair and the “stepper
function” to generate the next pair from that.)