OSDN Git Service

a59df18d82aeb5e50007472ca7c951336dda1393
[joypy/Thun.git] / docs / sphinx_docs / _build / html / _sources / notebooks / Generator_Programs.rst.txt
1 Using ``x`` to Generate Values
2 ==============================
3
4 Cf. jp-reprod.html
5
6 .. code:: python
7
8     from notebook_preamble import J, V, define
9
10 Consider the ``x`` combinator:
11
12 ::
13
14    x == dup i
15
16 We can apply it to a quoted program consisting of some value ``a`` and
17 some function ``B``:
18
19 ::
20
21    [a B] x
22    [a B] a B
23
24 Let ``B`` function ``swap`` the ``a`` with the quote and run some
25 function ``C`` on it to generate a new value ``b``:
26
27 ::
28
29    B == swap [C] dip
30
31    [a B] a B
32    [a B] a swap [C] dip
33    a [a B]      [C] dip
34    a C [a B]
35    b [a B]
36
37 Now discard the quoted ``a`` with ``rest`` then ``cons`` ``b``:
38
39 ::
40
41    b [a B] rest cons
42    b [B]        cons
43    [b B]
44
45 Altogether, this is the definition of ``B``:
46
47 ::
48
49    B == swap [C] dip rest cons
50
51 We can make a generator for the Natural numbers (0, 1, 2, …) by using
52 ``0`` for ``a`` and ``[dup ++]`` for ``[C]``:
53
54 ::
55
56    [0 swap [dup ++] dip rest cons]
57
58 Let’s try it:
59
60 .. code:: python
61
62     V('[0 swap [dup ++] dip rest cons] x')
63
64
65 .. parsed-literal::
66
67                                                . [0 swap [dup ++] dip rest cons] x
68                [0 swap [dup ++] dip rest cons] . x
69                [0 swap [dup ++] dip rest cons] . 0 swap [dup ++] dip rest cons
70              [0 swap [dup ++] dip rest cons] 0 . swap [dup ++] dip rest cons
71              0 [0 swap [dup ++] dip rest cons] . [dup ++] dip rest cons
72     0 [0 swap [dup ++] dip rest cons] [dup ++] . dip rest cons
73                                              0 . dup ++ [0 swap [dup ++] dip rest cons] rest cons
74                                            0 0 . ++ [0 swap [dup ++] dip rest cons] rest cons
75                                            0 1 . [0 swap [dup ++] dip rest cons] rest cons
76            0 1 [0 swap [dup ++] dip rest cons] . rest cons
77              0 1 [swap [dup ++] dip rest cons] . cons
78              0 [1 swap [dup ++] dip rest cons] . 
79
80
81 After one application of ``x`` the quoted program contains ``1`` and
82 ``0`` is below it on the stack.
83
84 .. code:: python
85
86     J('[0 swap [dup ++] dip rest cons] x x x x x pop')
87
88
89 .. parsed-literal::
90
91     0 1 2 3 4
92
93
94 ``direco``
95 ----------
96
97 .. code:: python
98
99     define('direco == dip rest cons')
100
101 .. code:: python
102
103     V('[0 swap [dup ++] direco] x')
104
105
106 .. parsed-literal::
107
108                                         . [0 swap [dup ++] direco] x
109                [0 swap [dup ++] direco] . x
110                [0 swap [dup ++] direco] . 0 swap [dup ++] direco
111              [0 swap [dup ++] direco] 0 . swap [dup ++] direco
112              0 [0 swap [dup ++] direco] . [dup ++] direco
113     0 [0 swap [dup ++] direco] [dup ++] . direco
114     0 [0 swap [dup ++] direco] [dup ++] . dip rest cons
115                                       0 . dup ++ [0 swap [dup ++] direco] rest cons
116                                     0 0 . ++ [0 swap [dup ++] direco] rest cons
117                                     0 1 . [0 swap [dup ++] direco] rest cons
118            0 1 [0 swap [dup ++] direco] . rest cons
119              0 1 [swap [dup ++] direco] . cons
120              0 [1 swap [dup ++] direco] . 
121
122
123 Making Generators
124 -----------------
125
126 We want to define a function that accepts ``a`` and ``[C]`` and builds
127 our quoted program:
128
129 ::
130
131             a [C] G
132    -------------------------
133       [a swap [C] direco]
134
135 Working in reverse:
136
137 ::
138
139    [a swap   [C] direco] cons
140    a [swap   [C] direco] concat
141    a [swap] [[C] direco] swap
142    a [[C] direco] [swap]
143    a [C] [direco] cons [swap]
144
145 Reading from the bottom up:
146
147 ::
148
149    G == [direco] cons [swap] swap concat cons
150    G == [direco] cons [swap] swoncat cons
151
152 .. code:: python
153
154     define('G == [direco] cons [swap] swoncat cons')
155
156 Let’s try it out:
157
158 .. code:: python
159
160     J('0 [dup ++] G')
161
162
163 .. parsed-literal::
164
165     [0 swap [dup ++] direco]
166
167
168 .. code:: python
169
170     J('0 [dup ++] G x x x pop')
171
172
173 .. parsed-literal::
174
175     0 1 2
176
177
178 Powers of 2
179 ~~~~~~~~~~~
180
181 .. code:: python
182
183     J('1 [dup 1 <<] G x x x x x x x x x pop')
184
185
186 .. parsed-literal::
187
188     1 2 4 8 16 32 64 128 256
189
190
191 ``[x] times``
192 ~~~~~~~~~~~~~
193
194 If we have one of these quoted programs we can drive it using ``times``
195 with the ``x`` combinator.
196
197 .. code:: python
198
199     J('23 [dup ++] G 5 [x] times')
200
201
202 .. parsed-literal::
203
204     23 24 25 26 27 [28 swap [dup ++] direco]
205
206
207 Generating Multiples of Three and Five
208 --------------------------------------
209
210 Look at the treatment of the Project Euler Problem One in the
211 “Developing a Program” notebook and you’ll see that we might be
212 interested in generating an endless cycle of:
213
214 ::
215
216    3 2 1 3 1 2 3
217
218 To do this we want to encode the numbers as pairs of bits in a single
219 int:
220
221 ::
222
223        3  2  1  3  1  2  3
224    0b 11 10 01 11 01 10 11 == 14811
225
226 And pick them off by masking with 3 (binary 11) and then shifting the
227 int right two bits.
228
229 .. code:: python
230
231     define('PE1.1 == dup [3 &] dip 2 >>')
232
233 .. code:: python
234
235     V('14811 PE1.1')
236
237
238 .. parsed-literal::
239
240                       . 14811 PE1.1
241                 14811 . PE1.1
242                 14811 . dup [3 &] dip 2 >>
243           14811 14811 . [3 &] dip 2 >>
244     14811 14811 [3 &] . dip 2 >>
245                 14811 . 3 & 14811 2 >>
246               14811 3 . & 14811 2 >>
247                     3 . 14811 2 >>
248               3 14811 . 2 >>
249             3 14811 2 . >>
250                3 3702 . 
251
252
253 If we plug ``14811`` and ``[PE1.1]`` into our generator form…
254
255 .. code:: python
256
257     J('14811 [PE1.1] G')
258
259
260 .. parsed-literal::
261
262     [14811 swap [PE1.1] direco]
263
264
265 …we get a generator that works for seven cycles before it reaches zero:
266
267 .. code:: python
268
269     J('[14811 swap [PE1.1] direco] 7 [x] times')
270
271
272 .. parsed-literal::
273
274     3 2 1 3 1 2 3 [0 swap [PE1.1] direco]
275
276
277 Reset at Zero
278 ~~~~~~~~~~~~~
279
280 We need a function that checks if the int has reached zero and resets it
281 if so.
282
283 .. code:: python
284
285     define('PE1.1.check == dup [pop 14811] [] branch')
286
287 .. code:: python
288
289     J('14811 [PE1.1.check PE1.1] G')
290
291
292 .. parsed-literal::
293
294     [14811 swap [PE1.1.check PE1.1] direco]
295
296
297 .. code:: python
298
299     J('[14811 swap [PE1.1.check PE1.1] direco] 21 [x] times')
300
301
302 .. parsed-literal::
303
304     3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 [0 swap [PE1.1.check PE1.1] direco]
305
306
307 (It would be more efficient to reset the int every seven cycles but
308 that’s a little beyond the scope of this article. This solution does
309 extra work, but not much, and we’re not using it “in production” as they
310 say.)
311
312 Run 466 times
313 ~~~~~~~~~~~~~
314
315 In the PE1 problem we are asked to sum all the multiples of three and
316 five less than 1000. It’s worked out that we need to use all seven
317 numbers sixty-six times and then four more.
318
319 .. code:: python
320
321     J('7 66 * 4 +')
322
323
324 .. parsed-literal::
325
326     466
327
328
329 If we drive our generator 466 times and sum the stack we get 999.
330
331 .. code:: python
332
333     J('[14811 swap [PE1.1.check PE1.1] direco] 466 [x] times')
334
335
336 .. parsed-literal::
337
338     3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 [57 swap [PE1.1.check PE1.1] direco]
339
340
341 .. code:: python
342
343     J('[14811 swap [PE1.1.check PE1.1] direco] 466 [x] times pop enstacken sum')
344
345
346 .. parsed-literal::
347
348     999
349
350
351 Project Euler Problem One
352 -------------------------
353
354 .. code:: python
355
356     define('PE1.2 == + dup [+] dip')
357
358 Now we can add ``PE1.2`` to the quoted program given to ``G``.
359
360 .. code:: python
361
362     J('0 0 0 [PE1.1.check PE1.1] G 466 [x [PE1.2] dip] times popop')
363
364
365 .. parsed-literal::
366
367     233168
368
369
370 A generator for the Fibonacci Sequence.
371 ---------------------------------------
372
373 Consider:
374
375 ::
376
377    [b a F] x
378    [b a F] b a F
379
380 The obvious first thing to do is just add ``b`` and ``a``:
381
382 ::
383
384    [b a F] b a +
385    [b a F] b+a
386
387 From here we want to arrive at:
388
389 ::
390
391    b [b+a b F]
392
393 Let’s start with ``swons``:
394
395 ::
396
397    [b a F] b+a swons
398    [b+a b a F]
399
400 Considering this quote as a stack:
401
402 ::
403
404    F a b b+a
405
406 We want to get it to:
407
408 ::
409
410    F b b+a b
411
412 So:
413
414 ::
415
416    F a b b+a popdd over
417    F b b+a b
418
419 And therefore:
420
421 ::
422
423    [b+a b a F] [popdd over] infra
424    [b b+a b F]
425
426 But we can just use ``cons`` to carry ``b+a`` into the quote:
427
428 ::
429
430    [b a F] b+a [popdd over] cons infra
431    [b a F] [b+a popdd over]      infra
432    [b b+a b F]
433
434 Lastly:
435
436 ::
437
438    [b b+a b F] uncons
439    b [b+a b F]
440
441 Putting it all together:
442
443 ::
444
445    F == + [popdd over] cons infra uncons
446    fib_gen == [1 1 F]
447
448 .. code:: python
449
450     define('fib == + [popdd over] cons infra uncons')
451
452 .. code:: python
453
454     define('fib_gen == [1 1 fib]')
455
456 .. code:: python
457
458     J('fib_gen 10 [x] times')
459
460
461 .. parsed-literal::
462
463     1 2 3 5 8 13 21 34 55 89 [144 89 fib]
464
465
466 Project Euler Problem Two
467 -------------------------
468
469    By considering the terms in the Fibonacci sequence whose values do
470    not exceed four million, find the sum of the even-valued terms.
471
472 Now that we have a generator for the Fibonacci sequence, we need a
473 function that adds a term in the sequence to a sum if it is even, and
474 ``pop``\ s it otherwise.
475
476 .. code:: python
477
478     define('PE2.1 == dup 2 % [+] [pop] branch')
479
480 And a predicate function that detects when the terms in the series
481 “exceed four million”.
482
483 .. code:: python
484
485     define('>4M == 4000000 >')
486
487 Now it’s straightforward to define ``PE2`` as a recursive function that
488 generates terms in the Fibonacci sequence until they exceed four million
489 and sums the even ones.
490
491 .. code:: python
492
493     define('PE2 == 0 fib_gen x [pop >4M] [popop] [[PE2.1] dip x] primrec')
494
495 .. code:: python
496
497     J('PE2')
498
499
500 .. parsed-literal::
501
502     4613732
503
504
505 Here’s the collected program definitions:
506
507 ::
508
509    fib == + swons [popdd over] infra uncons
510    fib_gen == [1 1 fib]
511
512    even == dup 2 %
513    >4M == 4000000 >
514
515    PE2.1 == even [+] [pop] branch
516    PE2 == 0 fib_gen x [pop >4M] [popop] [[PE2.1] dip x] primrec
517
518 Even-valued Fibonacci Terms
519 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
520
521 Using ``o`` for odd and ``e`` for even:
522
523 ::
524
525    o + o = e
526    e + e = e
527    o + e = o
528
529 So the Fibonacci sequence considered in terms of just parity would be:
530
531 ::
532
533    o o e o o e o o e o o e o o e o o e
534    1 1 2 3 5 8 . . .
535
536 Every third term is even.
537
538 .. code:: python
539
540     J('[1 0 fib] x x x')  # To start the sequence with 1 1 2 3 instead of 1 2 3.
541
542
543 .. parsed-literal::
544
545     1 1 2 [3 2 fib]
546
547
548 Drive the generator three times and ``popop`` the two odd terms.
549
550 .. code:: python
551
552     J('[1 0 fib] x x x [popop] dipd')
553
554
555 .. parsed-literal::
556
557     2 [3 2 fib]
558
559
560 .. code:: python
561
562     define('PE2.2 == x x x [popop] dipd')
563
564 .. code:: python
565
566     J('[1 0 fib] 10 [PE2.2] times')
567
568
569 .. parsed-literal::
570
571     2 8 34 144 610 2584 10946 46368 196418 832040 [1346269 832040 fib]
572
573
574 Replace ``x`` with our new driver function ``PE2.2`` and start our
575 ``fib`` generator at ``1 0``.
576
577 .. code:: python
578
579     J('0 [1 0 fib] PE2.2 [pop >4M] [popop] [[PE2.1] dip PE2.2] primrec')
580
581
582 .. parsed-literal::
583
584     4613732
585
586
587 How to compile these?
588 ---------------------
589
590 You would probably start with a special version of ``G``, and perhaps
591 modifications to the default ``x``?
592
593 An Interesting Variation
594 ------------------------
595
596 .. code:: python
597
598     define('codireco == cons dip rest cons')
599
600 .. code:: python
601
602     V('[0 [dup ++] codireco] x')
603
604
605 .. parsed-literal::
606
607                                      . [0 [dup ++] codireco] x
608                [0 [dup ++] codireco] . x
609                [0 [dup ++] codireco] . 0 [dup ++] codireco
610              [0 [dup ++] codireco] 0 . [dup ++] codireco
611     [0 [dup ++] codireco] 0 [dup ++] . codireco
612     [0 [dup ++] codireco] 0 [dup ++] . cons dip rest cons
613     [0 [dup ++] codireco] [0 dup ++] . dip rest cons
614                                      . 0 dup ++ [0 [dup ++] codireco] rest cons
615                                    0 . dup ++ [0 [dup ++] codireco] rest cons
616                                  0 0 . ++ [0 [dup ++] codireco] rest cons
617                                  0 1 . [0 [dup ++] codireco] rest cons
618            0 1 [0 [dup ++] codireco] . rest cons
619              0 1 [[dup ++] codireco] . cons
620              0 [1 [dup ++] codireco] . 
621
622
623 .. code:: python
624
625     define('G == [codireco] cons cons')
626
627 .. code:: python
628
629     J('230 [dup ++] G 5 [x] times pop')
630
631
632 .. parsed-literal::
633
634     230 231 232 233 234
635