1 # Square Spiral Example Joy Code
4 Here is the example of Joy code from the `README` file:
6 [[[abs]ii <=][[<>][pop !-]||]&&][[!-][[++]][[--]]ifte dip][[pop !-][--][++]ifte]ifte
8 It might seem unreadable but with a little familiarity it becomes just as
9 legible as any other notation. Some layout helps:
16 [[ !-] [[++]] [[--]] ifte dip]
17 [[pop !-] [--] [++] ifte ]
20 This function accepts two integers on the stack and increments or
21 decrements one of them such that the new pair of numbers is the next
22 coordinate pair in a square spiral (like the kind used to construct an
29 It's adapted from [the original code on StackOverflow](https://stackoverflow.com/questions/398299/looping-in-a-spiral/31864777#31864777):
32 > If all you're trying to do is generate the first N points in the spiral
33 > (without the original problem's constraint of masking to an N x M
34 > region), the code becomes very simple:
36 void spiral(const int N)
40 for(int i = 0; i < N; ++i)
42 cout << x << '\t' << y << '\n';
43 if(abs(x) <= abs(y) && (x != y || x >= 0))
44 x += ((y >= 0) ? 1 : -1);
46 y += ((x >= 0) ? -1 : 1);
52 I'm going to make a function that take two ints (`x` and `y`) and
53 generates the next pair, we'll turn it into a generator later using the
56 ### First Boolean Predicate
58 We need a function that computes `abs(x) <= abs(y)`, we can use `ii` to
59 apply `abs` to both values and then compare them
66 [_p [abs] ii <=] inscribe
101 ### Short-Circuiting Boolean Combinators
103 I've defined two short-circuiting Boolean combinators `&&` and `||` that
104 each accept two quoted predicate programs, run the first, and
105 conditionally run the second only if required (to compute the final
106 Boolean value). They run their predicate arguments `nullary`.
110 [&& [nullary] cons [nullary [false]] dip branch] inscribe
111 [|| [nullary] cons [nullary] dip [true] branch] inscribe
155 ### Translating the Conditionals
157 Given those, we can define `x != y || x >= 0` as:
159 _a == [!=] [pop 0 >=] ||
163 [_a [!=] [pop 0 >=] ||] inscribe
168 And `(abs(x) <= abs(y) && (x != y || x >= 0))` as:
174 [_b [_p] [_a] &&] inscribe
179 It's a little rough, but, as I say, with a little familiarity it becomes
195 23 -18 • [_p] [_a] &&
196 23 -18 [_p] • [_a] &&
197 23 -18 [_p] [_a] • &&
198 23 -18 [_p] [_a] • [nullary] cons [nullary [false]] dip branch
199 23 -18 [_p] [_a] [nullary] • cons [nullary [false]] dip branch
200 23 -18 [_p] [[_a] nullary] • [nullary [false]] dip branch
201 23 -18 [_p] [[_a] nullary] [nullary [false]] • dip branch
202 23 -18 [_p] • nullary [false] [[_a] nullary] branch
203 23 -18 [_p] • [stack] dinfrirst [false] [[_a] nullary] branch
204 23 -18 [_p] [stack] • dinfrirst [false] [[_a] nullary] branch
205 23 -18 [_p] [stack] • dip infrst [false] [[_a] nullary] branch
206 23 -18 • stack [_p] infrst [false] [[_a] nullary] branch
207 23 -18 [-18 23] • [_p] infrst [false] [[_a] nullary] branch
208 23 -18 [-18 23] [_p] • infrst [false] [[_a] nullary] branch
209 23 -18 [-18 23] [_p] • infra first [false] [[_a] nullary] branch
210 23 -18 • _p [-18 23] swaack first [false] [[_a] nullary] branch
211 23 -18 • [abs] ii <= [-18 23] swaack first [false] [[_a] nullary] branch
212 23 -18 [abs] • ii <= [-18 23] swaack first [false] [[_a] nullary] branch
213 23 • abs -18 abs <= [-18 23] swaack first [false] [[_a] nullary] branch
214 23 • -18 abs <= [-18 23] swaack first [false] [[_a] nullary] branch
215 23 -18 • abs <= [-18 23] swaack first [false] [[_a] nullary] branch
216 23 18 • <= [-18 23] swaack first [false] [[_a] nullary] branch
217 false • [-18 23] swaack first [false] [[_a] nullary] branch
218 false [-18 23] • swaack first [false] [[_a] nullary] branch
219 23 -18 [false] • first [false] [[_a] nullary] branch
220 23 -18 false • [false] [[_a] nullary] branch
221 23 -18 false [false] • [[_a] nullary] branch
222 23 -18 false [false] [[_a] nullary] • branch
235 ### The Increment / Decrement Branches
237 Turning to the branches of the main `if` statement:
239 x += ((y >= 0) ? 1 : -1);
241 Rewrite as a hybrid (pseudo-code) `ifte` expression:
243 [y >= 0] [x += 1] [X -= 1] ifte
245 Change each C phrase to Joy code:
247 [0 >=] [[++] dip] [[--] dip] ifte
249 Factor out the dip from each branch:
251 [0 >=] [[++]] [[--]] ifte dip
253 Similar logic applies to the other branch:
255 y += ((x >= 0) ? -1 : 1);
257 [x >= 0] [y -= 1] [y += 1] ifte
259 [pop 0 >=] [--] [++] ifte
261 ## Putting the Pieces Together
263 We can assemble the three functions we just defined in quotes and give
264 them them to the `ifte` combinator. With some arrangement to show off
265 the symmetry of the two branches, we have:
267 [[[abs] ii <=] [[<>] [pop !-] ||] &&]
268 [[ !-] [[++]] [[--]] ifte dip]
269 [[pop !-] [--] [++] ifte ]
277 [[ !-] [[++]] [[--]] ifte dip]
278 [[pop !-] [--] [++] ifte ]
286 As I was writing this up I realized that, since the `&&` combinator
287 doesn't consume the stack (below its quoted args), I can unquote the
288 predicate, swap the branches, and use the `branch` combinator instead of
291 [[abs] ii <=] [[<>] [pop !-] ||] &&
292 [[pop !-] [--] [++] ifte ]
293 [[ !-] [[++]] [[--]] ifte dip]
410 ## Turning it into a Generator with `x`
412 It can be used with the x combinator to make a kind of generator for
413 spiral square coordinates.
416 We can use `codireco` to make a generator
418 codireco == cons dip rest cons
420 It will look like this:
424 Here's a trace of how it works:
430 [0 [dup ++] codireco] [x] trace
433 [0 [dup ++] codireco] • x
434 [0 [dup ++] codireco] • 0 [dup ++] codireco
435 [0 [dup ++] codireco] 0 • [dup ++] codireco
436 [0 [dup ++] codireco] 0 [dup ++] • codireco
437 [0 [dup ++] codireco] 0 [dup ++] • codi reco
438 [0 [dup ++] codireco] 0 [dup ++] • cons dip reco
439 [0 [dup ++] codireco] [0 dup ++] • dip reco
440 • 0 dup ++ [0 [dup ++] codireco] reco
441 0 • dup ++ [0 [dup ++] codireco] reco
442 0 0 • ++ [0 [dup ++] codireco] reco
443 0 1 • [0 [dup ++] codireco] reco
444 0 1 [0 [dup ++] codireco] • reco
445 0 1 [0 [dup ++] codireco] • rest cons
446 0 1 [[dup ++] codireco] • cons
447 0 [1 [dup ++] codireco] •
449 0 [1 [dup ++] codireco]
458 But first we have to change the `spiral_next` function to work on a
459 quoted pair of integers, and leave a copy of the pair on the stack.
463 ---------------------
468 [x y] [spiral_next] infra
469 -------------------------------
474 [0 0] [spiral_next] infra
481 [[x y] [dup [spiral_next] infra] codireco]
485 [[0 0] [dup [spiral_next] infra] codireco]
487 There is a function `make_generator` that will build the generator for us
488 out of the value and stepper function:
490 [0 0] [dup [spiral_next] infra] make_generator
491 ----------------------------------------------------
492 [[0 0] [dup [spiral_next] infra] codireco]
501 Here it is in action:
505 [0 0] [dup [spiral_next] infra] make_generator x x x x pop
508 [0 0] [0 1] [-1 1] [-1 0]
510 Four `x` combinators, four pairs of coordinates.
512 Or you can leave out `dup` and let the value stay in the generator until you want it:
518 [0 0] [[spiral_next] infra] make_generator 50 [x] times first
525 So that's an example of Joy code. It's a straightforward translation of
526 the original. It's a little long for a single definition, you might
529 _spn_Pa == [abs] ii <=
530 _spn_Pb == [!=] [pop 0 >=] ||
531 _spn_P == [_spn_Pa] [_spn_Pb] &&
533 _spn_T == [ !-] [[++]] [[--]] ifte dip
534 _spn_E == [pop !-] [--] [++] ifte
536 spiral_next == _spn_P [_spn_E] [_spn_T] branch
538 This way it's easy to see that the function is a branch with two
539 quasi-symmetrical paths.
541 We then used this function to make a simple generator of coordinate
542 pairs, where the next pair in the series can be generated at any time by
543 using the `x` combinator on the generator (which is just a quoted
544 expression containing a copy of the current pair and the "stepper
545 function" to generate the next pair from that.)