OSDN Git Service

Update Square_Spiral notebook to use Joy kernel
[joypy/Thun.git] / docs / Square_Spiral.ipynb
1 {
2  "cells": [
3   {
4    "cell_type": "markdown",
5    "metadata": {},
6    "source": [
7     "# Square Spiral Example Joy Code"
8    ]
9   },
10   {
11    "cell_type": "markdown",
12    "metadata": {},
13    "source": [
14     "\n",
15     "Here is the example of Joy code from the `README` file:\n",
16     "\n",
17     "    [[[abs]ii <=][[<>][pop !-]||]&&][[!-][[++]][[--]]ifte dip][[pop !-][--][++]ifte]ifte\n",
18     "\n",
19     "It might seem unreadable but with a little familiarity it becomes just as\n",
20     "legible as any other notation.  Some layout helps:\n",
21     "\n",
22     "    [   [[abs] ii <=]\n",
23     "        [\n",
24     "            [<>] [pop !-] ||\n",
25     "        ] &&\n",
26     "    ]\n",
27     "    [[    !-] [[++]] [[--]] ifte dip]\n",
28     "    [[pop !-]  [--]   [++]  ifte    ]\n",
29     "    ifte\n",
30     "\n",
31     "This function accepts two integers on the stack and increments or\n",
32     "decrements one of them such that the new pair of numbers is the next\n",
33     "coordinate pair in a square spiral (like the kind used to construct an\n",
34     "Ulam Spiral).  \n",
35     "\n"
36    ]
37   },
38   {
39    "cell_type": "markdown",
40    "metadata": {},
41    "source": [
42     "## Original Form\n",
43     "\n",
44     "It's adapted from [the original code on StackOverflow](https://stackoverflow.com/questions/398299/looping-in-a-spiral/31864777#31864777):\n",
45     "\n",
46     "\n",
47     "> If all you're trying to do is generate the first N points in the spiral\n",
48     "> (without the original problem's constraint of masking to an N x M\n",
49     "> region), the code becomes very simple:\n",
50     "\n",
51     "    void spiral(const int N)\n",
52     "    {\n",
53     "        int x = 0;\n",
54     "        int y = 0;\n",
55     "        for(int i = 0; i < N; ++i)\n",
56     "        {\n",
57     "            cout << x << '\\t' << y << '\\n';\n",
58     "            if(abs(x) <= abs(y) && (x != y || x >= 0))\n",
59     "                x += ((y >= 0) ? 1 : -1);\n",
60     "            else\n",
61     "                y += ((x >= 0) ? -1 : 1);\n",
62     "        }\n",
63     "    }"
64    ]
65   },
66   {
67    "cell_type": "markdown",
68    "metadata": {},
69    "source": [
70     "## Translation to Joy\n",
71     "\n",
72     "I'm going to make a function that take two ints (`x` and `y`) and\n",
73     "generates the next pair, we'll turn it into a generator later using the\n",
74     "`x` combinator."
75    ]
76   },
77   {
78    "cell_type": "markdown",
79    "metadata": {},
80    "source": [
81     "### First Boolean Predicate\n",
82     "\n",
83     "We need a function that computes `abs(x) <= abs(y)`, we can use `ii` to\n",
84     "apply `abs` to both values and then compare them\n",
85     "with `<=`:\n",
86     "\n",
87     "    [abs] ii <="
88    ]
89   },
90   {
91    "cell_type": "code",
92    "execution_count": 1,
93    "metadata": {},
94    "outputs": [
95     {
96      "name": "stdout",
97      "output_type": "stream",
98      "text": []
99     }
100    ],
101    "source": [
102     "[_p [abs] ii <=] inscribe"
103    ]
104   },
105   {
106    "cell_type": "code",
107    "execution_count": 2,
108    "metadata": {},
109    "outputs": [
110     {
111      "name": "stdout",
112      "output_type": "stream",
113      "text": [
114       "23 -18"
115      ]
116     }
117    ],
118    "source": [
119     "clear 23 -18"
120    ]
121   },
122   {
123    "cell_type": "code",
124    "execution_count": 3,
125    "metadata": {},
126    "outputs": [
127     {
128      "name": "stdout",
129      "output_type": "stream",
130      "text": [
131       "      23 -18 • _p\n",
132       "      23 -18 • [abs] ii <=\n",
133       "23 -18 [abs] • ii <=\n",
134       "          23 • abs -18 abs <=\n",
135       "          23 • -18 abs <=\n",
136       "      23 -18 • abs <=\n",
137       "       23 18 • <=\n",
138       "       false • \n",
139       "\n",
140       "false"
141      ]
142     }
143    ],
144    "source": [
145     "[_p] trace"
146    ]
147   },
148   {
149    "cell_type": "code",
150    "execution_count": 4,
151    "metadata": {},
152    "outputs": [
153     {
154      "name": "stdout",
155      "output_type": "stream",
156      "text": []
157     }
158    ],
159    "source": [
160     "clear"
161    ]
162   },
163   {
164    "cell_type": "markdown",
165    "metadata": {},
166    "source": [
167     "### Short-Circuiting Boolean Combinators\n",
168     "\n",
169     "I've defined two short-circuiting Boolean combinators `&&` and `||` that\n",
170     "each accept two quoted predicate programs, run the first, and\n",
171     "conditionally run the second only if required (to compute the final\n",
172     "Boolean value).  They run their predicate arguments `nullary`."
173    ]
174   },
175   {
176    "cell_type": "code",
177    "execution_count": 5,
178    "metadata": {},
179    "outputs": [
180     {
181      "name": "stdout",
182      "output_type": "stream",
183      "text": []
184     }
185    ],
186    "source": [
187     "[&& [nullary] cons [nullary [false]] dip branch] inscribe\n",
188     "[|| [nullary] cons [nullary] dip [true] branch] inscribe"
189    ]
190   },
191   {
192    "cell_type": "code",
193    "execution_count": 6,
194    "metadata": {},
195    "outputs": [
196     {
197      "name": "stdout",
198      "output_type": "stream",
199      "text": [
200       "false"
201      ]
202     }
203    ],
204    "source": [
205     "clear \n",
206     "[true] [false] &&"
207    ]
208   },
209   {
210    "cell_type": "code",
211    "execution_count": 7,
212    "metadata": {},
213    "outputs": [
214     {
215      "name": "stdout",
216      "output_type": "stream",
217      "text": [
218       "false"
219      ]
220     }
221    ],
222    "source": [
223     "clear \n",
224     "[false] [true] &&"
225    ]
226   },
227   {
228    "cell_type": "code",
229    "execution_count": 8,
230    "metadata": {},
231    "outputs": [
232     {
233      "name": "stdout",
234      "output_type": "stream",
235      "text": [
236       "true"
237      ]
238     }
239    ],
240    "source": [
241     "clear \n",
242     "[true] [false] ||"
243    ]
244   },
245   {
246    "cell_type": "code",
247    "execution_count": 9,
248    "metadata": {},
249    "outputs": [
250     {
251      "name": "stdout",
252      "output_type": "stream",
253      "text": [
254       "true"
255      ]
256     }
257    ],
258    "source": [
259     "clear \n",
260     "[false] [true] ||"
261    ]
262   },
263   {
264    "cell_type": "code",
265    "execution_count": 10,
266    "metadata": {},
267    "outputs": [
268     {
269      "name": "stdout",
270      "output_type": "stream",
271      "text": []
272     }
273    ],
274    "source": [
275     "clear"
276    ]
277   },
278   {
279    "cell_type": "markdown",
280    "metadata": {},
281    "source": [
282     "### Translating the Conditionals\n",
283     "\n",
284     "Given those, we can define `x != y || x >= 0` as:\n",
285     "\n",
286     "    _a == [!=] [pop 0 >=] ||"
287    ]
288   },
289   {
290    "cell_type": "code",
291    "execution_count": 11,
292    "metadata": {},
293    "outputs": [
294     {
295      "name": "stdout",
296      "output_type": "stream",
297      "text": []
298     }
299    ],
300    "source": [
301     "[_a [!=] [pop 0 >=] ||] inscribe"
302    ]
303   },
304   {
305    "cell_type": "markdown",
306    "metadata": {},
307    "source": [
308     "And `(abs(x) <= abs(y) && (x != y || x >= 0))` as:\n",
309     "\n",
310     "    _b == [_p] [_a] &&"
311    ]
312   },
313   {
314    "cell_type": "code",
315    "execution_count": 12,
316    "metadata": {},
317    "outputs": [
318     {
319      "name": "stdout",
320      "output_type": "stream",
321      "text": []
322     }
323    ],
324    "source": [
325     "[_b [_p] [_a] &&] inscribe"
326    ]
327   },
328   {
329    "cell_type": "markdown",
330    "metadata": {},
331    "source": [
332     "It's a little rough, but, as I say, with a little familiarity it becomes\n",
333     "legible."
334    ]
335   },
336   {
337    "cell_type": "code",
338    "execution_count": 13,
339    "metadata": {},
340    "outputs": [
341     {
342      "name": "stdout",
343      "output_type": "stream",
344      "text": [
345       "23 -18"
346      ]
347     }
348    ],
349    "source": [
350     "clear 23 -18"
351    ]
352   },
353   {
354    "cell_type": "code",
355    "execution_count": 14,
356    "metadata": {},
357    "outputs": [
358     {
359      "name": "stdout",
360      "output_type": "stream",
361      "text": [
362       "                                      23 -18 • _b\n",
363       "                                      23 -18 • [_p] [_a] &&\n",
364       "                                 23 -18 [_p] • [_a] &&\n",
365       "                            23 -18 [_p] [_a] • &&\n",
366       "                            23 -18 [_p] [_a] • [nullary] cons [nullary [false]] dip branch\n",
367       "                  23 -18 [_p] [_a] [nullary] • cons [nullary [false]] dip branch\n",
368       "                  23 -18 [_p] [[_a] nullary] • [nullary [false]] dip branch\n",
369       "23 -18 [_p] [[_a] nullary] [nullary [false]] • dip branch\n",
370       "                                 23 -18 [_p] • nullary [false] [[_a] nullary] branch\n",
371       "                                 23 -18 [_p] • [stack] dinfrirst [false] [[_a] nullary] branch\n",
372       "                         23 -18 [_p] [stack] • dinfrirst [false] [[_a] nullary] branch\n",
373       "                         23 -18 [_p] [stack] • dip infrst [false] [[_a] nullary] branch\n",
374       "                                      23 -18 • stack [_p] infrst [false] [[_a] nullary] branch\n",
375       "                             23 -18 [-18 23] • [_p] infrst [false] [[_a] nullary] branch\n",
376       "                        23 -18 [-18 23] [_p] • infrst [false] [[_a] nullary] branch\n",
377       "                        23 -18 [-18 23] [_p] • infra first [false] [[_a] nullary] branch\n",
378       "                                      23 -18 • _p [-18 23] swaack first [false] [[_a] nullary] branch\n",
379       "                                      23 -18 • [abs] ii <= [-18 23] swaack first [false] [[_a] nullary] branch\n",
380       "                                23 -18 [abs] • ii <= [-18 23] swaack first [false] [[_a] nullary] branch\n",
381       "                                          23 • abs -18 abs <= [-18 23] swaack first [false] [[_a] nullary] branch\n",
382       "                                          23 • -18 abs <= [-18 23] swaack first [false] [[_a] nullary] branch\n",
383       "                                      23 -18 • abs <= [-18 23] swaack first [false] [[_a] nullary] branch\n",
384       "                                       23 18 • <= [-18 23] swaack first [false] [[_a] nullary] branch\n",
385       "                                       false • [-18 23] swaack first [false] [[_a] nullary] branch\n",
386       "                              false [-18 23] • swaack first [false] [[_a] nullary] branch\n",
387       "                              23 -18 [false] • first [false] [[_a] nullary] branch\n",
388       "                                23 -18 false • [false] [[_a] nullary] branch\n",
389       "                        23 -18 false [false] • [[_a] nullary] branch\n",
390       "         23 -18 false [false] [[_a] nullary] • branch\n",
391       "                                      23 -18 • false\n",
392       "                                23 -18 false • \n",
393       "\n",
394       "23 -18 false"
395      ]
396     }
397    ],
398    "source": [
399     "[_b] trace"
400    ]
401   },
402   {
403    "cell_type": "code",
404    "execution_count": 15,
405    "metadata": {},
406    "outputs": [
407     {
408      "name": "stdout",
409      "output_type": "stream",
410      "text": []
411     }
412    ],
413    "source": [
414     "clear"
415    ]
416   },
417   {
418    "cell_type": "markdown",
419    "metadata": {},
420    "source": [
421     "### The Increment / Decrement Branches\n",
422     "\n",
423     "Turning to the branches of the main `if` statement:\n",
424     "\n",
425     "    x += ((y >= 0) ? 1 : -1);\n",
426     "\n",
427     "Rewrite as a hybrid (pseudo-code) `ifte` expression:\n",
428     "\n",
429     "    [y >= 0] [x += 1] [X -= 1] ifte\n",
430     "\n",
431     "Change each C phrase to Joy code:\n",
432     "\n",
433     "    [0 >=] [[++] dip] [[--] dip] ifte\n",
434     "\n",
435     "Factor out the dip from each branch:\n",
436     "\n",
437     "    [0 >=] [[++]] [[--]] ifte dip\n",
438     "\n",
439     "Similar logic applies to the other branch:\n",
440     "\n",
441     "    y += ((x >= 0) ? -1 : 1);\n",
442     "\n",
443     "    [x >= 0] [y -= 1] [y += 1] ifte\n",
444     "\n",
445     "    [pop 0 >=] [--] [++] ifte"
446    ]
447   },
448   {
449    "cell_type": "markdown",
450    "metadata": {},
451    "source": [
452     "## Putting the Pieces Together\n",
453     "\n",
454     "We can assemble the three functions we just defined in quotes and give\n",
455     "them them to the `ifte` combinator.  With some arrangement to show off\n",
456     "the symmetry of the two branches, we have:\n",
457     "\n",
458     "    [[[abs] ii <=] [[<>] [pop !-] ||] &&]\n",
459     "    [[    !-] [[++]] [[--]] ifte dip]\n",
460     "    [[pop !-]  [--]   [++]  ifte    ]\n",
461     "    ifte"
462    ]
463   },
464   {
465    "cell_type": "code",
466    "execution_count": 16,
467    "metadata": {},
468    "outputs": [
469     {
470      "name": "stdout",
471      "output_type": "stream",
472      "text": []
473     }
474    ],
475    "source": [
476     "[spiral_next\n",
477     "\n",
478     "[_b]\n",
479     "[[    !-] [[++]] [[--]] ifte dip]\n",
480     "[[pop !-]  [--]   [++]  ifte    ]\n",
481     "ifte\n",
482     "\n",
483     "] inscribe"
484    ]
485   },
486   {
487    "cell_type": "markdown",
488    "metadata": {},
489    "source": [
490     "As I was writing this up I realized that, since the `&&` combinator\n",
491     "doesn't consume the stack (below its quoted args), I can unquote the\n",
492     "predicate, swap the branches, and use the `branch` combinator instead of\n",
493     "`ifte`:\n",
494     "\n",
495     "    [[abs] ii <=] [[<>] [pop !-] ||] &&\n",
496     "    [[pop !-]  [--]   [++]  ifte    ]\n",
497     "    [[    !-] [[++]] [[--]] ifte dip]\n",
498     "    branch"
499    ]
500   },
501   {
502    "cell_type": "markdown",
503    "metadata": {},
504    "source": [
505     "Let's try it out:"
506    ]
507   },
508   {
509    "cell_type": "code",
510    "execution_count": 17,
511    "metadata": {},
512    "outputs": [
513     {
514      "name": "stdout",
515      "output_type": "stream",
516      "text": [
517       "0 0"
518      ]
519     }
520    ],
521    "source": [
522     "clear 0 0"
523    ]
524   },
525   {
526    "cell_type": "code",
527    "execution_count": 18,
528    "metadata": {},
529    "outputs": [
530     {
531      "name": "stdout",
532      "output_type": "stream",
533      "text": [
534       "1 0"
535      ]
536     }
537    ],
538    "source": [
539     "spiral_next"
540    ]
541   },
542   {
543    "cell_type": "code",
544    "execution_count": 19,
545    "metadata": {},
546    "outputs": [
547     {
548      "name": "stdout",
549      "output_type": "stream",
550      "text": [
551       "1 -1"
552      ]
553     }
554    ],
555    "source": [
556     "spiral_next"
557    ]
558   },
559   {
560    "cell_type": "code",
561    "execution_count": 20,
562    "metadata": {},
563    "outputs": [
564     {
565      "name": "stdout",
566      "output_type": "stream",
567      "text": [
568       "0 -1"
569      ]
570     }
571    ],
572    "source": [
573     "spiral_next"
574    ]
575   },
576   {
577    "cell_type": "code",
578    "execution_count": 21,
579    "metadata": {},
580    "outputs": [
581     {
582      "name": "stdout",
583      "output_type": "stream",
584      "text": [
585       "-1 -1"
586      ]
587     }
588    ],
589    "source": [
590     "spiral_next"
591    ]
592   },
593   {
594    "cell_type": "code",
595    "execution_count": 22,
596    "metadata": {},
597    "outputs": [
598     {
599      "name": "stdout",
600      "output_type": "stream",
601      "text": [
602       "-1 0"
603      ]
604     }
605    ],
606    "source": [
607     "spiral_next"
608    ]
609   },
610   {
611    "cell_type": "code",
612    "execution_count": 23,
613    "metadata": {},
614    "outputs": [
615     {
616      "name": "stdout",
617      "output_type": "stream",
618      "text": [
619       "-1 1"
620      ]
621     }
622    ],
623    "source": [
624     "spiral_next"
625    ]
626   },
627   {
628    "cell_type": "code",
629    "execution_count": 24,
630    "metadata": {},
631    "outputs": [
632     {
633      "name": "stdout",
634      "output_type": "stream",
635      "text": [
636       "0 1"
637      ]
638     }
639    ],
640    "source": [
641     "spiral_next"
642    ]
643   },
644   {
645    "cell_type": "code",
646    "execution_count": 25,
647    "metadata": {},
648    "outputs": [
649     {
650      "name": "stdout",
651      "output_type": "stream",
652      "text": [
653       "1 1"
654      ]
655     }
656    ],
657    "source": [
658     "spiral_next"
659    ]
660   },
661   {
662    "cell_type": "code",
663    "execution_count": 26,
664    "metadata": {},
665    "outputs": [
666     {
667      "name": "stdout",
668      "output_type": "stream",
669      "text": [
670       "2 1"
671      ]
672     }
673    ],
674    "source": [
675     "spiral_next"
676    ]
677   },
678   {
679    "cell_type": "code",
680    "execution_count": 27,
681    "metadata": {},
682    "outputs": [
683     {
684      "name": "stdout",
685      "output_type": "stream",
686      "text": [
687       "2 0"
688      ]
689     }
690    ],
691    "source": [
692     "spiral_next"
693    ]
694   },
695   {
696    "cell_type": "code",
697    "execution_count": 28,
698    "metadata": {},
699    "outputs": [
700     {
701      "name": "stdout",
702      "output_type": "stream",
703      "text": [
704       "2 -1"
705      ]
706     }
707    ],
708    "source": [
709     "spiral_next"
710    ]
711   },
712   {
713    "cell_type": "code",
714    "execution_count": 29,
715    "metadata": {},
716    "outputs": [
717     {
718      "name": "stdout",
719      "output_type": "stream",
720      "text": [
721       "2 -2"
722      ]
723     }
724    ],
725    "source": [
726     "spiral_next"
727    ]
728   },
729   {
730    "cell_type": "code",
731    "execution_count": 30,
732    "metadata": {},
733    "outputs": [
734     {
735      "name": "stdout",
736      "output_type": "stream",
737      "text": [
738       "1 -2"
739      ]
740     }
741    ],
742    "source": [
743     "spiral_next"
744    ]
745   },
746   {
747    "cell_type": "code",
748    "execution_count": 31,
749    "metadata": {},
750    "outputs": [
751     {
752      "name": "stdout",
753      "output_type": "stream",
754      "text": [
755       "0 -2"
756      ]
757     }
758    ],
759    "source": [
760     "spiral_next"
761    ]
762   },
763   {
764    "cell_type": "code",
765    "execution_count": 32,
766    "metadata": {},
767    "outputs": [
768     {
769      "name": "stdout",
770      "output_type": "stream",
771      "text": [
772       "-1 -2"
773      ]
774     }
775    ],
776    "source": [
777     "spiral_next"
778    ]
779   },
780   {
781    "cell_type": "markdown",
782    "metadata": {},
783    "source": [
784     "## Turning it into a Generator with `x`\n",
785     "\n",
786     "It can be used with the x combinator to make a kind of generator for\n",
787     "spiral square coordinates.\n",
788     "\n",
789     "\n",
790     "We can use `codireco` to make a generator\n",
791     "\n",
792     "    codireco == cons dip rest cons\n",
793     "\n",
794     "It will look like this:\n",
795     "\n",
796     "    [value [F] codireco]\n",
797     "\n",
798     "Here's a trace of how it works:"
799    ]
800   },
801   {
802    "cell_type": "code",
803    "execution_count": 33,
804    "metadata": {},
805    "outputs": [
806     {
807      "name": "stdout",
808      "output_type": "stream",
809      "text": [
810       "           [0 [dup ++] codireco] • x\n",
811       "           [0 [dup ++] codireco] • 0 [dup ++] codireco\n",
812       "         [0 [dup ++] codireco] 0 • [dup ++] codireco\n",
813       "[0 [dup ++] codireco] 0 [dup ++] • codireco\n",
814       "[0 [dup ++] codireco] 0 [dup ++] • codi reco\n",
815       "[0 [dup ++] codireco] 0 [dup ++] • cons dip reco\n",
816       "[0 [dup ++] codireco] [0 dup ++] • dip reco\n",
817       "                                 • 0 dup ++ [0 [dup ++] codireco] reco\n",
818       "                               0 • dup ++ [0 [dup ++] codireco] reco\n",
819       "                             0 0 • ++ [0 [dup ++] codireco] reco\n",
820       "                             0 1 • [0 [dup ++] codireco] reco\n",
821       "       0 1 [0 [dup ++] codireco] • reco\n",
822       "       0 1 [0 [dup ++] codireco] • rest cons\n",
823       "         0 1 [[dup ++] codireco] • cons\n",
824       "         0 [1 [dup ++] codireco] • \n",
825       "\n",
826       "0 [1 [dup ++] codireco]"
827      ]
828     }
829    ],
830    "source": [
831     "clear\n",
832     "\n",
833     "[0 [dup ++] codireco] [x] trace"
834    ]
835   },
836   {
837    "cell_type": "code",
838    "execution_count": 34,
839    "metadata": {},
840    "outputs": [
841     {
842      "name": "stdout",
843      "output_type": "stream",
844      "text": []
845     }
846    ],
847    "source": [
848     "clear"
849    ]
850   },
851   {
852    "cell_type": "markdown",
853    "metadata": {},
854    "source": [
855     "But first we have to change the `spiral_next` function to work on a\n",
856     "quoted pair of integers, and leave a copy of the pair on the stack.\n",
857     "From:\n",
858     "\n",
859     "       y x spiral_next\n",
860     "    ---------------------\n",
861     "            y' x'\n",
862     "\n",
863     "to:\n",
864     "\n",
865     "       [x y] [spiral_next] infra\n",
866     "    -------------------------------\n",
867     "               [x' y']"
868    ]
869   },
870   {
871    "cell_type": "code",
872    "execution_count": 35,
873    "metadata": {},
874    "outputs": [
875     {
876      "name": "stdout",
877      "output_type": "stream",
878      "text": [
879       "[0 1]"
880      ]
881     }
882    ],
883    "source": [
884     "[0 0] [spiral_next] infra"
885    ]
886   },
887   {
888    "cell_type": "markdown",
889    "metadata": {},
890    "source": [
891     "So our generator is:\n",
892     "\n",
893     "    [[x y] [dup [spiral_next] infra] codireco]\n",
894     "\n",
895     "Or rather:\n",
896     "\n",
897     "    [[0 0] [dup [spiral_next] infra] codireco]\n",
898     "\n",
899     "There is a function `make_generator` that will build the generator for us\n",
900     "out of the value and stepper function:\n",
901     "\n",
902     "       [0 0] [dup [spiral_next] infra] make_generator\n",
903     "    ----------------------------------------------------\n",
904     "         [[0 0] [dup [spiral_next] infra] codireco]"
905    ]
906   },
907   {
908    "cell_type": "code",
909    "execution_count": 36,
910    "metadata": {},
911    "outputs": [
912     {
913      "name": "stdout",
914      "output_type": "stream",
915      "text": []
916     }
917    ],
918    "source": [
919     "clear"
920    ]
921   },
922   {
923    "cell_type": "markdown",
924    "metadata": {},
925    "source": [
926     "Here it is in action:"
927    ]
928   },
929   {
930    "cell_type": "code",
931    "execution_count": 37,
932    "metadata": {},
933    "outputs": [
934     {
935      "name": "stdout",
936      "output_type": "stream",
937      "text": [
938       "[0 0] [0 1] [-1 1] [-1 0]"
939      ]
940     }
941    ],
942    "source": [
943     "[0 0] [dup [spiral_next] infra] make_generator x x x x pop"
944    ]
945   },
946   {
947    "cell_type": "markdown",
948    "metadata": {},
949    "source": [
950     "Four `x` combinators, four pairs of coordinates.\n",
951     "\n",
952     "Or you can leave out `dup` and let the value stay in the generator until you want it:"
953    ]
954   },
955   {
956    "cell_type": "code",
957    "execution_count": 38,
958    "metadata": {},
959    "outputs": [
960     {
961      "name": "stdout",
962      "output_type": "stream",
963      "text": [
964       "[2 4]"
965      ]
966     }
967    ],
968    "source": [
969     "clear\n",
970     "\n",
971     "[0 0] [[spiral_next] infra] make_generator 50 [x] times first"
972    ]
973   },
974   {
975    "cell_type": "markdown",
976    "metadata": {},
977    "source": [
978     "## Conclusion\n",
979     "\n",
980     "So that's an example of Joy code.  It's a straightforward translation of\n",
981     "the original.  It's a little long for a single definition, you might\n",
982     "break it up like so:\n",
983     "\n",
984     "    _spn_Pa == [abs] ii <=\n",
985     "    _spn_Pb == [!=] [pop 0 >=] ||\n",
986     "    _spn_P  == [_spn_Pa] [_spn_Pb] &&\n",
987     "    \n",
988     "    _spn_T == [    !-] [[++]] [[--]] ifte dip\n",
989     "    _spn_E == [pop !-]  [--]   [++]  ifte\n",
990     "\n",
991     "    spiral_next == _spn_P [_spn_E] [_spn_T] branch\n",
992     "\n",
993     "This way it's easy to see that the function is a branch with two\n",
994     "quasi-symmetrical paths.\n",
995     "\n",
996     "We then used this function to make a simple generator of coordinate\n",
997     "pairs, where the next pair in the series can be generated at any time by\n",
998     "using the `x` combinator on the generator (which is just a quoted\n",
999     "expression containing a copy of the current pair and the \"stepper\n",
1000     "function\" to generate the next pair from that.)"
1001    ]
1002   }
1003  ],
1004  "metadata": {
1005   "kernelspec": {
1006    "display_name": "Joypy",
1007    "language": "",
1008    "name": "thun"
1009   },
1010   "language_info": {
1011    "file_extension": ".joy",
1012    "mimetype": "text/plain",
1013    "name": "Joy"
1014   }
1015  },
1016  "nbformat": 4,
1017  "nbformat_minor": 2
1018 }