OSDN Git Service

Clean up Zipper notebook.
[joypy/Thun.git] / docs / Square_Spiral.rst
1 Square Spiral Example Joy Code
2 ==============================
3
4 Here is the example of Joy code from the ``README`` file:
5
6 ::
7
8    [[[abs]ii <=][[<>][pop !-]||]&&][[!-][[++]][[--]]ifte dip][[pop !-][--][++]ifte]ifte
9
10 It might seem unreadable but with a little familiarity it becomes just
11 as legible as any other notation. Some layout helps:
12
13 ::
14
15    [   [[abs] ii <=]
16        [
17            [<>] [pop !-] ||
18        ] &&
19    ]
20    [[    !-] [[++]] [[--]] ifte dip]
21    [[pop !-]  [--]   [++]  ifte    ]
22    ifte
23
24 This function accepts two integers on the stack and increments or
25 decrements one of them such that the new pair of numbers is the next
26 coordinate pair in a square spiral (like the kind used to construct an
27 Ulam Spiral).
28
29 Original Form
30 -------------
31
32 It’s adapted from `the original code on
33 StackOverflow <https://stackoverflow.com/questions/398299/looping-in-a-spiral/31864777#31864777>`__:
34
35    If all you’re trying to do is generate the first N points in the
36    spiral (without the original problem’s constraint of masking to an N
37    x M region), the code becomes very simple:
38
39 ::
40
41    void spiral(const int N)
42    {
43        int x = 0;
44        int y = 0;
45        for(int i = 0; i < N; ++i)
46        {
47            cout << x << '\t' << y << '\n';
48            if(abs(x) <= abs(y) && (x != y || x >= 0))
49                x += ((y >= 0) ? 1 : -1);
50            else
51                y += ((x >= 0) ? -1 : 1);
52        }
53    }
54
55 Translation to Joy
56 ------------------
57
58 I’m going to make a function that take two ints (``x`` and ``y``) and
59 generates the next pair, we’ll turn it into a generator later using the
60 ``x`` combinator.
61
62 First Boolean Predicate
63 ~~~~~~~~~~~~~~~~~~~~~~~
64
65 We need a function that computes ``abs(x) <= abs(y)``, we can use ``ii``
66 to apply ``abs`` to both values and then compare them with ``<=``:
67
68 ::
69
70    [abs] ii <=
71
72 .. code:: Joy
73
74     [_p [abs] ii <=] inscribe
75
76
77 .. parsed-literal::
78
79     
80
81 .. code:: Joy
82
83     clear 23 -18
84
85
86 .. parsed-literal::
87
88     23 -18
89
90 .. code:: Joy
91
92     [_p] trace
93
94
95 .. parsed-literal::
96
97           23 -18 • _p
98           23 -18 • [abs] ii <=
99     23 -18 [abs] • ii <=
100               23 • abs -18 abs <=
101               23 • -18 abs <=
102           23 -18 • abs <=
103            23 18 • <=
104            false • 
105     
106     false
107
108 .. code:: Joy
109
110     clear
111
112
113 .. parsed-literal::
114
115     
116
117 Short-Circuiting Boolean Combinators
118 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
119
120 I’ve defined two short-circuiting Boolean combinators ``&&`` and ``||``
121 that each accept two quoted predicate programs, run the first, and
122 conditionally run the second only if required (to compute the final
123 Boolean value). They run their predicate arguments ``nullary``.
124
125 .. code:: Joy
126
127     [&& [nullary] cons [nullary [false]] dip branch] inscribe
128     [|| [nullary] cons [nullary] dip [true] branch] inscribe
129
130
131 .. parsed-literal::
132
133     
134
135 .. code:: Joy
136
137     clear 
138     [true] [false] &&
139
140
141 .. parsed-literal::
142
143     false
144
145 .. code:: Joy
146
147     clear 
148     [false] [true] &&
149
150
151 .. parsed-literal::
152
153     false
154
155 .. code:: Joy
156
157     clear 
158     [true] [false] ||
159
160
161 .. parsed-literal::
162
163     true
164
165 .. code:: Joy
166
167     clear 
168     [false] [true] ||
169
170
171 .. parsed-literal::
172
173     true
174
175 .. code:: Joy
176
177     clear
178
179
180 .. parsed-literal::
181
182     
183
184 Translating the Conditionals
185 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
186
187 Given those, we can define ``x != y || x >= 0`` as:
188
189 ::
190
191    _a == [!=] [pop 0 >=] ||
192
193 .. code:: Joy
194
195     [_a [!=] [pop 0 >=] ||] inscribe
196
197
198 .. parsed-literal::
199
200     
201
202 And ``(abs(x) <= abs(y) && (x != y || x >= 0))`` as:
203
204 ::
205
206    _b == [_p] [_a] &&
207
208 .. code:: Joy
209
210     [_b [_p] [_a] &&] inscribe
211
212
213 .. parsed-literal::
214
215     
216
217 It’s a little rough, but, as I say, with a little familiarity it becomes
218 legible.
219
220 .. code:: Joy
221
222     clear 23 -18
223
224
225 .. parsed-literal::
226
227     23 -18
228
229 .. code:: Joy
230
231     [_b] trace
232
233
234 .. parsed-literal::
235
236                                           23 -18 • _b
237                                           23 -18 • [_p] [_a] &&
238                                      23 -18 [_p] • [_a] &&
239                                 23 -18 [_p] [_a] • &&
240                                 23 -18 [_p] [_a] • [nullary] cons [nullary [false]] dip branch
241                       23 -18 [_p] [_a] [nullary] • cons [nullary [false]] dip branch
242                       23 -18 [_p] [[_a] nullary] • [nullary [false]] dip branch
243     23 -18 [_p] [[_a] nullary] [nullary [false]] • dip branch
244                                      23 -18 [_p] • nullary [false] [[_a] nullary] branch
245                                      23 -18 [_p] • [stack] dinfrirst [false] [[_a] nullary] branch
246                              23 -18 [_p] [stack] • dinfrirst [false] [[_a] nullary] branch
247                              23 -18 [_p] [stack] • dip infrst [false] [[_a] nullary] branch
248                                           23 -18 • stack [_p] infrst [false] [[_a] nullary] branch
249                                  23 -18 [-18 23] • [_p] infrst [false] [[_a] nullary] branch
250                             23 -18 [-18 23] [_p] • infrst [false] [[_a] nullary] branch
251                             23 -18 [-18 23] [_p] • infra first [false] [[_a] nullary] branch
252                                           23 -18 • _p [-18 23] swaack first [false] [[_a] nullary] branch
253                                           23 -18 • [abs] ii <= [-18 23] swaack first [false] [[_a] nullary] branch
254                                     23 -18 [abs] • ii <= [-18 23] swaack first [false] [[_a] nullary] branch
255                                               23 • abs -18 abs <= [-18 23] swaack first [false] [[_a] nullary] branch
256                                               23 • -18 abs <= [-18 23] swaack first [false] [[_a] nullary] branch
257                                           23 -18 • abs <= [-18 23] swaack first [false] [[_a] nullary] branch
258                                            23 18 • <= [-18 23] swaack first [false] [[_a] nullary] branch
259                                            false • [-18 23] swaack first [false] [[_a] nullary] branch
260                                   false [-18 23] • swaack first [false] [[_a] nullary] branch
261                                   23 -18 [false] • first [false] [[_a] nullary] branch
262                                     23 -18 false • [false] [[_a] nullary] branch
263                             23 -18 false [false] • [[_a] nullary] branch
264              23 -18 false [false] [[_a] nullary] • branch
265                                           23 -18 • false
266                                     23 -18 false • 
267     
268     23 -18 false
269
270 .. code:: Joy
271
272     clear
273
274
275 .. parsed-literal::
276
277     
278
279 The Increment / Decrement Branches
280 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
281
282 Turning to the branches of the main ``if`` statement:
283
284 ::
285
286    x += ((y >= 0) ? 1 : -1);
287
288 Rewrite as a hybrid (pseudo-code) ``ifte`` expression:
289
290 ::
291
292    [y >= 0] [x += 1] [X -= 1] ifte
293
294 Change each C phrase to Joy code:
295
296 ::
297
298    [0 >=] [[++] dip] [[--] dip] ifte
299
300 Factor out the dip from each branch:
301
302 ::
303
304    [0 >=] [[++]] [[--]] ifte dip
305
306 Similar logic applies to the other branch:
307
308 ::
309
310    y += ((x >= 0) ? -1 : 1);
311
312    [x >= 0] [y -= 1] [y += 1] ifte
313
314    [pop 0 >=] [--] [++] ifte
315
316 Putting the Pieces Together
317 ---------------------------
318
319 We can assemble the three functions we just defined in quotes and give
320 them them to the ``ifte`` combinator. With some arrangement to show off
321 the symmetry of the two branches, we have:
322
323 ::
324
325    [[[abs] ii <=] [[<>] [pop !-] ||] &&]
326    [[    !-] [[++]] [[--]] ifte dip]
327    [[pop !-]  [--]   [++]  ifte    ]
328    ifte
329
330 .. code:: Joy
331
332     [spiral_next
333     
334     [_b]
335     [[    !-] [[++]] [[--]] ifte dip]
336     [[pop !-]  [--]   [++]  ifte    ]
337     ifte
338     
339     ] inscribe
340
341
342 .. parsed-literal::
343
344     
345
346 As I was writing this up I realized that, since the ``&&`` combinator
347 doesn’t consume the stack (below its quoted args), I can unquote the
348 predicate, swap the branches, and use the ``branch`` combinator instead
349 of ``ifte``:
350
351 ::
352
353    [[abs] ii <=] [[<>] [pop !-] ||] &&
354    [[pop !-]  [--]   [++]  ifte    ]
355    [[    !-] [[++]] [[--]] ifte dip]
356    branch
357
358 Let’s try it out:
359
360 .. code:: Joy
361
362     clear 0 0
363
364
365 .. parsed-literal::
366
367     0 0
368
369 .. code:: Joy
370
371     spiral_next
372
373
374 .. parsed-literal::
375
376     1 0
377
378 .. code:: Joy
379
380     spiral_next
381
382
383 .. parsed-literal::
384
385     1 -1
386
387 .. code:: Joy
388
389     spiral_next
390
391
392 .. parsed-literal::
393
394     0 -1
395
396 .. code:: Joy
397
398     spiral_next
399
400
401 .. parsed-literal::
402
403     -1 -1
404
405 .. code:: Joy
406
407     spiral_next
408
409
410 .. parsed-literal::
411
412     -1 0
413
414 .. code:: Joy
415
416     spiral_next
417
418
419 .. parsed-literal::
420
421     -1 1
422
423 .. code:: Joy
424
425     spiral_next
426
427
428 .. parsed-literal::
429
430     0 1
431
432 .. code:: Joy
433
434     spiral_next
435
436
437 .. parsed-literal::
438
439     1 1
440
441 .. code:: Joy
442
443     spiral_next
444
445
446 .. parsed-literal::
447
448     2 1
449
450 .. code:: Joy
451
452     spiral_next
453
454
455 .. parsed-literal::
456
457     2 0
458
459 .. code:: Joy
460
461     spiral_next
462
463
464 .. parsed-literal::
465
466     2 -1
467
468 .. code:: Joy
469
470     spiral_next
471
472
473 .. parsed-literal::
474
475     2 -2
476
477 .. code:: Joy
478
479     spiral_next
480
481
482 .. parsed-literal::
483
484     1 -2
485
486 .. code:: Joy
487
488     spiral_next
489
490
491 .. parsed-literal::
492
493     0 -2
494
495 .. code:: Joy
496
497     spiral_next
498
499
500 .. parsed-literal::
501
502     -1 -2
503
504 Turning it into a Generator with ``x``
505 --------------------------------------
506
507 It can be used with the x combinator to make a kind of generator for
508 spiral square coordinates.
509
510 We can use ``codireco`` to make a generator
511
512 ::
513
514    codireco == cons dip rest cons
515
516 It will look like this:
517
518 ::
519
520    [value [F] codireco]
521
522 Here’s a trace of how it works:
523
524 .. code:: Joy
525
526     clear
527     
528     [0 [dup ++] codireco] [x] trace
529
530
531 .. parsed-literal::
532
533                [0 [dup ++] codireco] • x
534                [0 [dup ++] codireco] • 0 [dup ++] codireco
535              [0 [dup ++] codireco] 0 • [dup ++] codireco
536     [0 [dup ++] codireco] 0 [dup ++] • codireco
537     [0 [dup ++] codireco] 0 [dup ++] • codi reco
538     [0 [dup ++] codireco] 0 [dup ++] • cons dip reco
539     [0 [dup ++] codireco] [0 dup ++] • dip reco
540                                      • 0 dup ++ [0 [dup ++] codireco] reco
541                                    0 • dup ++ [0 [dup ++] codireco] reco
542                                  0 0 • ++ [0 [dup ++] codireco] reco
543                                  0 1 • [0 [dup ++] codireco] reco
544            0 1 [0 [dup ++] codireco] • reco
545            0 1 [0 [dup ++] codireco] • rest cons
546              0 1 [[dup ++] codireco] • cons
547              0 [1 [dup ++] codireco] • 
548     
549     0 [1 [dup ++] codireco]
550
551 .. code:: Joy
552
553     clear
554
555
556 .. parsed-literal::
557
558     
559
560 But first we have to change the ``spiral_next`` function to work on a
561 quoted pair of integers, and leave a copy of the pair on the stack.
562 From:
563
564 ::
565
566       y x spiral_next
567    ---------------------
568            y' x'
569
570 to:
571
572 ::
573
574       [x y] [spiral_next] infra
575    -------------------------------
576               [x' y']
577
578 .. code:: Joy
579
580     [0 0] [spiral_next] infra
581
582
583 .. parsed-literal::
584
585     [0 1]
586
587 So our generator is:
588
589 ::
590
591    [[x y] [dup [spiral_next] infra] codireco]
592
593 Or rather:
594
595 ::
596
597    [[0 0] [dup [spiral_next] infra] codireco]
598
599 There is a function ``make_generator`` that will build the generator for
600 us out of the value and stepper function:
601
602 ::
603
604       [0 0] [dup [spiral_next] infra] make_generator
605    ----------------------------------------------------
606         [[0 0] [dup [spiral_next] infra] codireco]
607
608 .. code:: Joy
609
610     clear
611
612
613 .. parsed-literal::
614
615     
616
617 Here it is in action:
618
619 .. code:: Joy
620
621     [0 0] [dup [spiral_next] infra] make_generator x x x x pop
622
623
624 .. parsed-literal::
625
626     [0 0] [0 1] [-1 1] [-1 0]
627
628 Four ``x`` combinators, four pairs of coordinates.
629
630 Or you can leave out ``dup`` and let the value stay in the generator
631 until you want it:
632
633 .. code:: Joy
634
635     clear
636     
637     [0 0] [[spiral_next] infra] make_generator 50 [x] times first
638
639
640 .. parsed-literal::
641
642     [2 4]
643
644 Conclusion
645 ----------
646
647 So that’s an example of Joy code. It’s a straightforward translation of
648 the original. It’s a little long for a single definition, you might
649 break it up like so:
650
651 ::
652
653    _spn_Pa == [abs] ii <=
654    _spn_Pb == [!=] [pop 0 >=] ||
655    _spn_P  == [_spn_Pa] [_spn_Pb] &&
656
657    _spn_T == [    !-] [[++]] [[--]] ifte dip
658    _spn_E == [pop !-]  [--]   [++]  ifte
659
660    spiral_next == _spn_P [_spn_E] [_spn_T] branch
661
662 This way it’s easy to see that the function is a branch with two
663 quasi-symmetrical paths.
664
665 We then used this function to make a simple generator of coordinate
666 pairs, where the next pair in the series can be generated at any time by
667 using the ``x`` combinator on the generator (which is just a quoted
668 expression containing a copy of the current pair and the “stepper
669 function” to generate the next pair from that.)