OSDN Git Service

Add a README to the docs/ dir.
[joypy/Thun.git] / docs / source / notebooks / BigNums.md
1 # BigNums in Joy
2
3 Most of the implementations of Thun support 
4 [BigNums](https://en.wikipedia.org/wiki/BigNum), either built-in or as
5 libraries, but some host languages and systems do not.  In those cases it
6 would be well to have a pure-Joy implementation.
7
8 We can model bignums as a pair of a Boolean value for the sign and a list
9 of integers for the digits.  The bool will be the first item on a list
10 followed by zero or more integer digits, with the Least Significant digit
11 at the top (closest to the head of the list.)  E.g.:
12
13     [true 1]
14
15 Our *base* for the digits will be dictated by the size of the integers
16 supported by the host system.  Let's imagine we're using 32-bit signed
17 ints, so our base will be not 10, but 2³¹.  (We're ignoring the sign
18 bit.)
19
20     joy? 2 31 pow
21     2147483648
22
23 So our digits are not 0..9, but 0..2147483647
24
25 ### ≡ `base`
26
27 We can `inscribe` a constant function `base` to keep this value handy.
28
29     2147483648
30     joy? unit [base] swoncat
31     [base 2147483648]
32     joy? inscribe
33
34 It's a little "wrong" to use the
35 dictionary to store values like this, however, this is how Forth does it
36 and if your design is good it works fine.  Just be careful, and wash
37 your hands afterward.
38
39 This also permits a kind of parameterization.  E.g. let's say we wanted
40 to use base 10 for our digits, maybe during debugging.  All that requires
41 is to rebind the symbol `base` to 10.
42
43     [base 10] inscribe
44
45 ## Converting Between Host BigNums and Joy BigNums
46
47 We will work with one of the Joy interpreters that has bignums already so
48 we can convert "native" ints to our Joy bignums and vice versa.  This
49 will be helpful to check our work.  Later we can deal with converting to
50 and from strings (which this Joy doesn't have anyway, so it's probably
51 fine to defer.)
52
53 To get the sign bool we can just use `!-` ("not negative") and to get the
54 list of digits we repeatedly `divmod` the number by our `base`:
55
56 ### ≡ `moddiv`
57
58 We will want the results in the opposite order, so let's define a little
59 helper function to do that:
60
61     [moddiv divmod swap] inscribe
62
63 ### ≡ `get-digit`
64
65     [get-digit base moddiv] inscribe
66
67 We keep it up until we get to zero.  This suggests a `while` loop:
68
69     [0 >] [get-digit] while
70
71 Let's try it:
72
73     joy? 1234567890123456789012345678901234567890
74     1234567890123456789012345678901234567890
75     
76     joy? [0 >] [get-digit] while 
77     1312754386 1501085485 57659106 105448366 58 0
78
79 We need to `pop` at the end to ditch that zero.
80
81     [0 >] [get-digit] while pop
82
83 But we want these numbers in a list.  The naive way using `infra`
84 generates them in the reverse order of what we would like.
85
86     joy? [1234567890123456789012345678901234567890]
87     [1234567890123456789012345678901234567890]
88     
89     joy? [[0 >] [get-digit] while pop]
90     [1234567890123456789012345678901234567890] [[0 >] [get-digit] while pop]
91     
92     joy? infra
93     [58 105448366 57659106 1501085485 1312754386]
94
95 We could just reverse the list, but it's more efficient to build the
96 result list in the order we want. We construct a simple recursive
97 function.  (TODO: link to the recursion combinators notebook.)
98
99 The predicate will check that our number is yet positive:
100
101     [0 <=]
102
103 When we find the zero we will discard it and start a list:
104
105     [pop []]
106
107 But until we do find the zero, get digits:
108
109     [get-digit]
110
111 Once we have found all the digits and ditched the zero and put our
112 initial empty list on the stack we `cons` up the digits we have found:
113
114     [i cons] genrec
115
116 Let's try it:
117
118     joy? 1234567890123456789012345678901234567890
119     1234567890123456789012345678901234567890
120     
121     joy? [0 <=] [pop []] [get-digit] [i cons] genrec
122     [1312754386 1501085485 57659106 105448366 58]
123
124 Okay.
125
126 ### Representing Zero
127
128 This will return the empty list for zero:
129
130     joy? 0 [0 <=] [pop []] [get-digit] [i cons] genrec
131     []
132
133 I think this is better than returning `[0]` because that amounts to a
134 single leading zero.
135
136     [true]   is "0"
137     [true 0] is "00"
138
139 Eh?
140
141 ### ≡ `digitalize`
142
143 Let's `inscribe` this function under the name `digitalize`:
144
145     [digitalize [0 <=] [pop []] [get-digit] [i cons] genrec] inscribe
146
147 Putting it all together we have `!-` for the sign and `abs digitalize`
148 for the digits, followed by `cons`:
149
150     [!-] [abs digitalize] cleave cons
151
152 ### ≡ `to-bignum`
153
154     [to-bignum [!-] [abs digitalize] cleave cons] inscribe
155
156 ### Converting from Joy BigNums to Host BigNums
157
158 To convert a bignum into a host integer we need to keep a "power" value
159 on the stack, setting it up and discarding it at the end, as well as an
160 accumulator value starting at zero. We will deal with the sign bit later.
161
162     rest 1 0 rolldown
163
164 So the problem is to derive:
165
166        1 0 [digits...] [F] step
167     ------------------------------
168               result
169
170 Where `F` is:
171
172               power acc digit F
173     ---------------------------------------
174        (power*base) (acc + (power*digit)
175
176 Now this is an interesting function. The first thing I noticed is that it
177 has two results that can be computed independently, suggesting a form
178 like:
179
180     [G] [H] clop popdd
181
182 (Then I noticed that `power *` is a sub-function of both `G` and `H`, but
183 let's not overthink it, eh?)
184
185 So for the first result (the next power) we want:
186
187     G == popop base *
188
189 And for the result:
190
191     H == rolldown * +
192
193 ### ≡ `add-digit`
194
195 Let's call this `add-digit`:
196
197     [add-digit [popop base *] [rolldown * +] clop popdd] inscribe
198
199 Try it out:
200
201     [true 1312754386 1501085485 57659106 105448366 58]
202     joy? rest 1 0 rolldown
203
204     1 0 [1312754386 1501085485 57659106 105448366 58]
205
206     joy? [add-digit] step
207     45671926166590716193865151022383844364247891968 1234567890123456789012345678901234567890
208
209     joy? popd
210     1234567890123456789012345678901234567890
211
212 ### ≡ `from-bignum′`
213
214     [from-bignum′ rest 1 0 rolldown [add-digit] step popd] inscribe
215
216 Try it out:
217
218     joy? 1234567890123456789012345678901234567890 to-bignum
219     [true 1312754386 1501085485 57659106 105448366 58]
220
221     joy? from-bignum′
222     1234567890123456789012345678901234567890
223
224 Not bad.
225
226 ### What about that sign bit?
227
228 Time to deal with that.
229
230 Consider a Joy bignum:
231
232     [true 1312754386 1501085485 57659106 105448366 58]
233
234 To get the sign bit would just be `first`.
235
236     [true 1312754386 1501085485 57659106 105448366 58]
237
238     joy? [from-bignum′] [first] cleave
239     1234567890123456789012345678901234567890 true
240
241 Then use the sign flag to negate the int if the bignum was negative:
242
243     [neg] [] branch
244
245 ### ≡ `from-bignum`
246
247 This gives:
248
249     [from-bignum [from-bignum′] [first] cleave [neg] [] branch] inscribe
250
251
252 ## Our Source Code So Far
253
254     [base 2147483648] inscribe
255     [moddiv divmod swap] inscribe
256     [get-digit base moddiv] inscribe
257     [digitalize [0 <=] [pop []] [get-digit] [i cons] genrec] inscribe
258     [to-bignum [!-] [abs digitalize] cleave cons] inscribe
259
260     [add-digit [popop base *] [rolldown * +] clop popdd] inscribe
261     [from-bignum′.prep rest 1 0 rolldown] inscribe
262     [from-bignum′ from-bignum′.prep [add-digit] step popd] inscribe
263     [from-bignum [from-bignum′] [first] cleave [neg] [] branch] inscribe
264
265
266 ## Addition of Like Signs
267
268 ### `add-digits`
269
270 Let's figure out how to add two lists of digits.  We will assume that the
271 signs are the same (both lists of digits represent numbers of the same
272 sign, both positive or both negative.) We're going to want a recursive
273 function, of course, but it's not quite a standard *hylomorphism* for (at
274 least) two reasons:
275
276 - We're tearing down two lists simultaneously.
277 - They might not be the same length.
278
279 There are two base cases: two empty lists or one empty list, the
280 recursive branch is taken only if both lists are non-empty.
281
282 We will also need an inital `false` value for a carry flag.  This implies
283 the following structure:
284
285     false rollup [add-digits.P] [add-digits.THEN] [add-digits.R0] [add-digits.R1] genrec
286
287 ### The predicate
288
289 The situation will be like this, a Boolean flag followed by two lists of
290 digits:
291
292     bool [a ...] [b ...] add-digits.P
293
294 The predicate must evaluate to `false` *iff* both lists are non-`null`:
295
296     add-digits.P == [null] ii \/
297
298 ### The base cases
299
300 On the non-recursive branch of the `genrec` we have to decide between
301 three cases, but because addition is commutative we can lump together the
302 first two:
303
304     bool [] [b ...] add-digits.THEN
305     bool [a ...] [] add-digits.THEN
306     
307     bool [] [] add-digits.THEN
308
309 So we have an `ifte` expression:
310
311     add-digits.THEN == [add-digits.THEN.P] [add-digits.THEN.THEN] [add-digits.THEN.ELSE] ifte
312
313 Let's define the predicate:
314
315     add-digits.THEN.P == [null] ii /\
316
317 So `add-digits.THEN.THEN` deals with the case of both lists being empty,
318 and the `add-digits.THEN.ELSE` branch deals with one list of digits being
319 longer than the other.
320
321 ### One list empty
322
323 In the cases where one of the two lists (but not both) is empty:
324
325     carry [a ...] [] add-digits.THEN.ELSE
326     carry [] [b ...] add-digits.THEN.ELSE
327
328 We first get rid of the empty list:
329
330     [null] [pop] [popd] ifte
331
332 ### ≡ `ditch-empty-list`
333
334     [ditch-empty-list [null] [pop] [popd] ifte] inscribe
335
336     add-digits.THEN.ELSE == ditch-empty-list add-digits.THEN.ELSE′
337
338 Now we have:
339
340     carry [n ...] add-digits.THEN.ELSE′
341
342 This is just `add-carry-to-digits` which we will derive in a moment, but
343 first a side-quest...
344
345 ### `add-with-carry`
346
347 To get ahead of ourselves a bit, we will want some function
348 `add-with-carry` that accepts a bool and two ints and leaves behind a new
349 int and a new Boolean carry flag. With some abuse of notation we can
350 treat bools as ints (type punning as in Python) and write:
351
352           carry a b add-with-carry
353     ---------------------------------
354             (a+b+carry) carry′
355
356 (I find it interesting that this function accepts the carry from below
357 the int args but returns it above the result.  Hmm...)
358
359 ### ≡ `bool-to-int`
360
361     [bool-to-int [0] [1] branch] inscribe
362
363 We can use this function to convert the carry flag to an integer and then
364 add it to the sum of the two digits:
365
366     [bool-to-int] dipd + +
367
368 So the first part of `add-with-carry` is `[bool-to-int] dipd + +` to get
369 the total, then we need to do `base mod` to get the new digit and `base >=`
370 to get the new carry flag.  Factoring give us:
371
372     base [mod] [>=] clop
373
374 Put it all together and we have:
375
376     [add-with-carry.0 [bool-to-int] dipd + +] inscribe
377     [add-with-carry.1 base [mod] [>=] clop] inscribe
378     [add-with-carry add-with-carry.0 add-with-carry.1] inscribe
379
380 ### Now back to `add-carry-to-digits`
381
382 This should be a very simple recursive function.  It accepts a Boolean
383 `carry` flag and a non-empty list of digits (the list is only going to be
384 non-empty on the first iteration, after that we have to check it
385 ourselves because we may have emptied it of digits and still have a
386 `true` `carry` flag) and it returns a list of digits, consuming the carry
387 flag.
388
389     add-carry-to-digits == [actd.P] [actd.THEN] [actd.R0] [actd.R1] genrec
390
391 The predicate is the carry flag itself inverted:
392
393     actd.P == pop not
394
395 The base case simply discards the carry flag:
396
397     actd.THEN == popd
398
399 So:
400
401     add-carry-to-digits == [pop not] [popd] [actd.R0] [actd.R1] genrec
402
403 That leaves the recursive branch:
404
405     true [n ...] actd.R0 [add-carry-to-digits] actd.R1
406
407 -or-
408
409     true [] actd.R0 [add-carry-to-digits] actd.R1
410
411 We know that the Boolean value is `true`. We also know that the list will
412 be non-empty, but only on the first iteration of the `genrec`. It may be
413 that the list is empty on a later iteration.
414
415 The `actd.R0` function should check the list.
416
417     actd.R0 == [null] [actd.R0.THEN] [actd.R0.ELSE] ifte
418
419 ### If it's empty...
420
421        true [] actd.R0.THEN [add-carry-to-digits] actd.R1
422     --------------------------------------------------------
423                  1 false [] [add-carry-to-digits] i cons
424
425 What we're seeing here is that `actd.R0.THEN` leaves the empty list of
426 digits on the stack, converts the carry flag to `false` and leave 1 on
427 the stack to be picked up by `actd.R1` and `cons`'d onto the list of
428 digits (e.g.: 999 -> 1000, it's the new 1.)
429
430 This implies:
431
432     actd.R1 == i cons
433
434 And:
435
436     actd.R0.THEN == popd 1 false rolldown
437
438 We have the results in this order `1 false []` rather than some other
439 arrangement to be compatible (same types and order) with the result of
440 the other branch, which we now derive.
441
442 ### If the list of digits isn't empty...
443
444 With `actd.R1 == i cons` as above we have:
445
446     true [a ...] actd.R0.ELSE [add-carry-to-digits] i cons
447
448 We want to get out that `a` value and use `add-with-carry` here:
449
450        true 0 a add-with-carry [...] [add-carry-to-digits] i cons
451     ----------------------------------------------------------------
452            (a+1) carry         [...] [add-carry-to-digits] i cons
453
454 This leaves behind the new digit (a+1) for `actd.R1` and the new carry
455 flag for the next iteration.
456
457 So here is the specification of `actd.R0.ELSE`:
458
459          true [a ...] actd.R0.ELSE
460     -----------------------------------
461        true 0 a add-with-carry [...]
462
463 It accepts a Boolean value and a non-empty list on the stack and is
464 responsible for `uncons`'ing `a` and `add-with-carry` and the initial 0:
465
466                      true [a ...] . 0 swap
467                    true 0 [a ...] . uncons
468                    true 0 a [...] . [add-with-carry] dip
469     true 0 a add-with-carry [...] .
470
471 ### ≡ `actd.R0.ELSE`
472
473     [actd.R0.ELSE 0 swap uncons [add-with-carry] dip] inscribe
474
475 Putting it all together:
476
477     [bool-to-int [0] [1] branch] inscribe
478     [ditch-empty-list [null] [pop] [popd] ifte] inscribe
479
480     [add-with-carry.0 [bool-to-int] dipd + +] inscribe
481     [add-with-carry.1 base [mod] [>=] clop] inscribe
482     [add-with-carry add-with-carry.0 add-with-carry.1] inscribe
483
484     [actd.R0.THEN popd 1 false rolldown] inscribe
485     [actd.R0.ELSE 0 swap uncons [add-with-carry] dip] inscribe
486     [actd.R0 [null] [actd.R0.THEN] [actd.R0.ELSE] ifte] inscribe
487
488     [add-carry-to-digits [pop not] [popd] [actd.R0] [i cons] genrec] inscribe
489
490
491 We can set `base` to 10 to see it in action with familiar decimal digits:
492
493     joy? [base 10] inscribe
494
495 Let's add a carry to 999:
496
497     joy? true [9 9 9]
498     true [9 9 9]
499
500     joy? add-carry-to-digits
501     [0 0 0 1]
502
503 Not bad!  Recall that our digits are stored in with the Most Significant
504 Digit at the bottom of the list.
505
506 Let's add another carry:
507
508     joy? true swap
509     true [0 0 0 1]
510     
511     joy? add-carry-to-digits
512     [1 0 0 1]
513
514 What if we make the just the first digit into 9?
515     
516     joy? 9 swons
517     [9 1 0 0 1]
518     
519     joy? true swap
520     true [9 1 0 0 1]
521     
522     joy? add-carry-to-digits
523     [0 2 0 0 1]
524
525 Excellent!
526
527 And adding `false` does nothing, yes?
528
529     joy? false swap
530     false [0 2 0 0 1]
531     
532     joy? add-carry-to-digits
533     [0 2 0 0 1]
534
535 Wonderful!
536
537 So that handles the cases where one of the two lists (but not both) is
538 empty.
539
540     add-digits.THEN.ELSE == ditch-empty-list add-carry-to-digits
541
542 ### Both lists empty
543
544 If both lists are empty we discard one list and check the carry to
545 determine our result as described above:
546
547     bool [] [] add-digits.THEN.THEN
548
549 Simple enough:
550
551     bool [] [] . pop
552     bool [] . swap
553     [] bool . [] [1 swons] branch
554
555 True branch:
556
557     [] true . [] [1 swons] branch
558     [] .
559
560 False branch:
561
562     [] false . [] [1 swons] branch
563     [] . 1 swons
564     [1] .
565
566 So:
567
568     add-digits.THEN.THEN == pop swap [] [1 swons] branch
569
570 Here are the definitions, ready to `inscribe`:
571
572     [add-digits.THEN.THEN pop swap [] [1 swons] branch] inscribe
573     [add-digits.THEN.ELSE ditch-empty-list add-carry-to-digits] inscribe
574     [add-digits.THEN [[null] ii /\] [add-digits.THEN.THEN] [add-digits.THEN.ELSE] ifte] inscribe
575
576 ## And recur...
577
578 Now we go back and derive the recursive branch that is taken only if both
579 lists are non-empty.
580
581     bool [a ...] [b ...] add-digits.R0 [add-digits′] add-digits.R1
582
583 We just need to knock out those recursive branch functions
584 `add-digits.R0` and `add-digits.R1` and we're done.
585
586 First we will want to `uncons` the digits.  Let's write a function that
587 just does that:
588
589     [uncons] ii swapd
590
591 Try it:
592
593     joy? [1 2 3] [4 5 6]
594     [1 2 3] [4 5 6]
595     
596     joy? [uncons] ii swapd
597     1 4 [2 3] [5 6]
598
599 ### ≡ `uncons-two`
600
601 We could call this `uncons-two`:
602
603     [uncons-two [uncons] ii swapd] inscribe
604
605 This brings us to:
606
607     bool a b [...] [...] add-digits.R0′ [add-digits′] add-digits.R1
608
609 It's at this point that we'll want to employ the `add-with-carry`
610 function:
611
612     bool a b [...] [...] [add-with-carry] dipd add-digits.R0″ [add-digits'] add-digits.R1
613
614     bool a b add-with-carry [...] [...] add-digits.R0″ [add-digits'] add-digits.R1
615
616     (a+b) bool [...] [...] add-digits.R0″ [add-digits'] add-digits.R1
617
618 If we postulate a `cons` in our `add-digits.R1` function...
619
620     (a+b) bool [...] [...] add-digits.R0″ [add-digits'] i cons
621
622 Then it seems like we're done?  `add-digits.R0″` is nothing?
623
624     add-digits.R0 == uncons-two [add-with-carry] dipd
625     
626     add-digits.R1 == i cons
627
628 ### `add-digits`
629
630     add-digits == false rollup [add-digits.P] [add-digits.THEN] [add-digits.R0] [i cons] genrec
631
632 The source code so far is now:
633
634     [bool-to-int [0] [1] branch] inscribe
635     [ditch-empty-list [null] [pop] [popd] ifte] inscribe
636     [uncons-two [uncons] ii swapd] inscribe
637
638     [add-with-carry.0 [bool-to-int] dipd + +] inscribe
639     [add-with-carry.1 base [mod] [>=] clop] inscribe
640     [add-with-carry add-with-carry.0 add-with-carry.1] inscribe
641
642     [actd.R0.THEN popd 1 false rolldown] inscribe
643     [actd.R0.ELSE 0 swap uncons [add-with-carry] dip] inscribe
644     [actd.R0 [null] [actd.R0.THEN] [actd.R0.ELSE] ifte] inscribe
645
646     [add-carry-to-digits [pop not] [popd] [actd.R0] [i cons] genrec] inscribe
647
648     [add-digits.R0 uncons-two [add-with-carry] dipd] inscribe
649
650     [add-digits.THEN.THEN pop swap [] [1 swons] branch] inscribe
651     [add-digits.THEN.ELSE ditch-empty-list add-carry-to-digits] inscribe
652     [add-digits.THEN [[null] ii /\] [add-digits.THEN.THEN] [add-digits.THEN.ELSE] ifte] inscribe
653
654     [add-digits′ [[null] ii \/] [add-digits.THEN] [add-digits.R0] [i cons] genrec] inscribe
655     [add-digits false rollup add-digits′] inscribe
656
657 Let's set `base` to 10 and try it out:
658
659     joy? [base 10] inscribe
660
661     joy? 12345 to-bignum
662     [true 5 4 3 2 1]
663     
664     joy? rest
665     [5 4 3 2 1]
666     
667     joy? 999 to-bignum
668     [5 4 3 2 1] [true 9 9 9]
669     
670     joy? rest
671     [5 4 3 2 1] [9 9 9]
672     
673     joy? add-digits
674     [4 4 3 3 1]
675     
676     joy? true swons
677     [true 4 4 3 3 1]
678     
679     joy? from-bignum
680     13344
681
682     joy? 12345 999 +
683     13344 13344
684
685 Neat!
686
687 ### `add-bignums`
688
689 There is one more thing we have to do to use this: we have to deal with
690 the signs.
691
692     add-bignums [add-bignums.P] [add-bignums.THEN] [add-bignums.ELSE] ifte
693
694 To check are they the same sign?
695
696 With:
697
698     [xor [] [not] branch] inscribe
699     [nxor xor not] inscribe
700
701 We have:
702
703     add-bignums.P == [first] ii nxor
704
705 If they are the same sign (both positive or both negative) we can use
706 `uncons` to keep one of the sign Boolean flags around and reuse it at the
707 end, and `rest` to discard the other, then `add-digits` to add the
708 digits, then `cons` that flag we saved onto the result digits list:
709
710     add-bignums.THEN == [uncons] dip rest add-digits cons
711
712 If they are not both positive or both negative then we negate one of them
713 and subtract instead (adding unlikes is actually subtraction):
714
715     add-bignums.ELSE == neg-bignum sub-bignums
716
717 So here we go:
718
719     [same-sign [first] ii xor not] inscribe
720     [add-like-bignums [uncons] dip rest add-digits cons] inscribe
721
722     [add-bignums [same-sign] [add-like-bignums] [neg-bignum sub-bignums] ifte] inscribe
723
724 But we haven't implemented `neg-bignum` or `sub-bignums` yet...
725
726 We'll get to those in a moment, but first an interlude.
727
728 ## Interlude: `list-combiner`
729
730 Let's review the form of our function `add-digits` (eliding the preamble
731 `false rollup`) and `add-digits.THEN`:
732
733     add-digits′ == [add-digits.P] [add-digits.THEN] [add-digits.R0] [add-digits.R1] genrec
734
735     add-digits.THEN == [add-digits.THEN.P] [add-digits.THEN.THEN] [add-digits.THEN.ELSE] ifte
736
737 Recall also:
738
739          add-digits.P == [null] ii \/
740     add-digits.THEN.P == [null] ii /\
741
742 Generalizing the names:
743
744        F == [P] [THEN] [R0] [R1] genrec
745     THEN == [THEN.P] [THEN.THEN] [THEN.ELSE] ifte
746
747 With auxiliary definitions:
748
749     null-two == [null] ii
750     both-null == null-two /\
751     either-or-both-null == null-two \/
752
753 Rename predicates:
754
755        F == [either-or-both-null] [THEN] [R0] [R1] genrec
756     THEN == [both-null] [THEN.THEN] [THEN.ELSE] ifte
757
758 Substitute `THEN`:
759
760        F == [either-or-both-null] [[both-null] [THEN.THEN] [THEN.ELSE] ifte] [R0] [R1] genrec
761
762 This is a little awkward, so let's pretend that we have a new combinator
763 `two-list-genrec` that accepts four quotes and does `F`:
764
765     F == [THEN.THEN] [THEN.ELSE] [R0] [R1] two-list-genrec
766
767 So `THEN.THEN` handles the (non-recursive) case of both lists being
768 empty, `THEN.ELSE` handles the (non-recursive) case of one or the other
769 list being empty, and `R0 [F] R1` handles the (recursive) case of both
770 lists being non-empty.
771
772 Recall that our `R1` is just `i cons`, we can fold that in to the
773 definition of another new combinator that combines two lists into one:
774
775     list-combiner-genrec == [i cons] two-list-genrec
776
777 So:
778
779     F == [both-empty] [one-empty] [both-non-empty] list-combiner-genrec
780
781 Then for `add-digits′` we would have:
782
783         both-empty == pop swap [] [1 swons] branch
784          one-empty == ditch-empty-list add-carry-to-digits
785     both-non-empty == uncons-two [add-with-carry] dipd
786
787     add-digits′ == [both-empty] [one-empty] [both-non-empty] list-combiner-genrec
788
789 Which would expand into:
790
791     add-digits′ == [either-or-both-null]
792                    [[both-null] [both-empty] [one-empty] ifte]
793                    [both-non-empty]
794                    [i cons]
795                    genrec
796
797 It's pretty straight forward to make a functions that converts the three
798 quotes into the expanded form (a kind of "macro") but you might want to
799 separate that from the actual `genrec` evaluation.  It would be better to
800 run the "macro" once, append the `[genrec]` quote to the resulting form,
801 and `inscribe` that, rather than putting the "macro" into the definition.
802 That way you avoid re-evaluating the "macro" on each iteration.
803
804 The simplification of the expanded form to the simpler version by coining
805 the `list-combiner-genrec` function is the "semantic compression" aspect
806 of factoring.  If you choose your seams and names well, the code is
807 (relatively) self-descriptive.
808
809 In any event, now that we know what's going on, we don't actually need
810 the "macro", we can just write out the expanded version directly.
811
812 Source code:
813
814     [null-two [null] ii] inscribe
815     [both-null null-two /\] inscribe
816     [either-or-both-null null-two \/] inscribe
817
818     [add-digits.both-empty pop swap [] [1 swons] branch] inscribe
819     [add-digits.one-empty ditch-empty-list add-carry-to-digits] inscribe
820     [add-digits.both-non-empty uncons-two [add-with-carry] dipd] inscribe
821
822     [add-digits′ [either-or-both-null] [[both-null] [add-digits.both-empty] [add-digits.one-empty] ifte] [add-digits.both-non-empty] [i cons] genrec] inscribe
823
824
825 ## ≡ `neg-bignum`
826
827 Well, that was fun!  And we'll reuse it in a moment when we derive `sub-bignums`.
828 But for now let's clear our palate with a nice simple function: `neg-bignum`.
829
830 To negate a Joy bignum you just invert the Boolean value at the head of the list.
831
832     neg-bignum == [not] infra
833
834
835 ## Subtraction of Like Signs
836
837 Subtraction is similar to addition in that it's a simple recursive algorithm that works digit-by-digit.
838 It has the same three cases as well, so we can reuse the `list-combiner-genrec` "macro" that
839 we specified (but did not yet derive) a moment ago.
840
841        sub-digits == initial-carry sub-digits'
842       sub-digits' == [both-empty] [one-empty] [both-non-empty] list-combiner-genrec
843
844 Okay, we're almost ready to implement subtraction, but there's a wrinkle!
845 When we subtract a smaller (absolute) value from a larger (absolute)
846 value there's no problem:
847
848     10 - 5 = 5
849
850 But I don't know the algorithm to subtract a larger number from a smaller
851 one:
852
853     5 - 10 = ???
854
855 The answer is -5, of course, but what's the algorithm?  How to make the
856 computer figure that out?
857
858 We make use of the simple algebraic identity:
859
860     a - b = -(b - a)
861
862 So if we want to subtract a larger number `a` from a smaller one `b` we
863 can instead subtract the smaller from the larger and invert the sign:
864
865     5 - 10 = -(10 - 5)
866
867 To do this we need a function `gt-digits` that will tell us which of two
868 digit lists represents the larger integer.
869
870
871 ### ≡ `length`
872
873 Gentle reader, it was at this time that I realized I don't have a list length function yet!
874
875     [length [pop ++] step_zero] inscribe
876
877 ### Comparing Lists of Integers
878
879 We only need to compare the digits of the numbers if one list of digits is longer than the other.
880 We could use `length` on both lists and then `cmp`:
881
882     a b [G] [E] [L] cmp
883
884 If the top list is longer than the second list the function should return `true`,
885 and if the top list is shorter than the second list the function should return `false`,
886
887     dup2 [length] ii [true] [E] [false] cmp
888
889 If both lists are non-empty we have to compare digits starting with the ends.
890
891     E == zip reverse compare-digits
892
893 But this is inefficient!  The `length` function will traverse each list once,
894 then the `zip` function will traverse both lists and build a new list of pairs,
895 then the `reverse` function will traverse that list and rebuild it,
896 then the `compare-digits` will traverse that list looking for unequal pairs...
897 It's a lot of work that we don't really want or need to do.
898
899 ### A More Efficient Comparison
900
901 What we really want is a function that iterates through both lists together
902 and:
903
904 - If the top list is empty and the second list isn't then the whole function should return `false`.
905 - If the top list is non-empty and the second list is empty then the whole function should return `true`.
906 - If both lists are empty we start checking pairs of digits (that we got from the recursive case.)
907 - If both lists are non-empty we `uncons-two` digits for later comparison and recur.
908
909 Let's start designing the function.
910
911        [...] [...] F
912     -------------------
913            bool
914
915 We will need a list on which to put pairs
916
917     F == <<{} F′
918
919        [] [...] [...] F′
920     ----------------------
921             bool
922
923 It's a recursive function:
924
925     F′ == [P] [THEN] [R0] [R1] genrec
926     
927 The predicate tests whether both of the two input lists are non-empty:
928
929     P = null-two \/
930
931 (We defined this as `either-or-both-null` above.)
932
933 Let's look at the recursive case first:
934
935        [...] [b ...] [a ...] R0 [F] R1
936     -------------------------------------------
937           [[b a] ...] [...] [...] F
938
939 So `R0` transfers items from the source list to the pairs list,
940 let's call it `shift-pair`:
941
942        [...] [b ...] [a ...] shift-pair
943     --------------------------------------
944            [[b a] ...] [...] [...]
945
946 I'll leave that as an exercise for the reader for now.
947
948 `R1` is just `i` (this is a `tailrec` function.)
949
950     F == <<{} [either-or-both-null] [THEN] [shift-pair] tailrec
951
952 Now let's derive `THEN`, there are three cases:
953
954     [pairs...] [] [] THEN
955     [pairs...] [b ...] [] THEN
956     [pairs...] [] [a ...] THEN
957
958 We can model this as a pair of `ifte` expressions, one nested in the other:
959
960     [P] [THEN′] [[P′] [THEN′′] [ELSE′] ifte] ifte
961
962 But in the event we won't need the inner `ifte`, see below.
963
964 The first predicate should check if both lists are empty:
965
966     P == null-two /\
967
968 (We defined this as `both-null` above.)
969
970 If both lists are empty we check the pairs:
971
972     THEN′ == popop compare-pairs
973
974 Otherwise if the top list is empty we return `false`, otherwise `true`,
975 and since this is a destructive operation we don't have to use `ifte` here:
976
977     THEN == [both-null] [popop compare-pairs] [popopd null] ifte
978
979     F == <<{} [either-or-both-null] [THEN] [shift-pair] tailrec
980
981 Now we just have to write `compare-pairs` (and `shift-pair`.)
982
983 ### ≡ `shift-pair`
984
985     [pair-up unit cons] inscribe
986
987     [shift-pair uncons-two [pair-up swons] dipd] inscribe
988
989
990 ### Compare Pairs
991
992 This function takes a list of pairs of digits (ints) and compares
993 them until it finds an unequal pair or runs out of pairs.
994
995 We are implementing "greater than" (b > a) so if we run out of digits
996 that means the two numbers were equal, and so we return `false`:
997
998     F == [null] [pop false] [R0] [R1] genrec
999
1000 That leaves the recursive branch:
1001
1002     [[b a] ...] R0 [F] R1
1003
1004 I figure we're going to want some sort of `ifte`.  (But this turns out to
1005 be a mistake!)
1006
1007     [[b a] ...] [P] [THEN] [F] ifte
1008
1009 if b > a we can stop and report `true`, otherwise we discard the pair and recur.
1010
1011     P == first i >
1012
1013     THEN == pop true
1014
1015 Note that that fails to discard the pair!
1016
1017     [[b a] ...] [first i >] [pop true] [F] ifte
1018
1019 If b <= a this would just re-run `F` with the same list!
1020
1021 Oops!  D'oh!  I didn't think it through properly.
1022
1023 We need to distinguish all three case (> = <) so we want to use `cmp`:
1024
1025     [[b a] ...] unswons i [G] [F] [L] cmp
1026
1027 Becomes:
1028
1029     [...] b a [G] [F] [L] cmp
1030
1031 Note that we recur on equality (that is our `E` function is just `F` itself).
1032
1033 If we the digits are not equal we can quit the loop with the answer:
1034
1035     [...] b a [pop true] [F] [pop false] cmp
1036
1037 So:
1038
1039     R0 == unswons i [pop true]
1040
1041     R1 == [pop false] cmp
1042
1043 ### ≡ `compare-pairs`
1044
1045     [compare-pairs.R0 unswons i [pop true]] inscribe
1046     [compare-pairs.R1 [pop false] cmp] inscribe
1047     [compare-pairs [null] [pop false] [compare-pairs.R0] [compare-pairs.R1] genrec] inscribe
1048
1049 ### ≡ `gt-digits`
1050
1051     [gt-digits.THEN [both-null] [popop compare-pairs] [popopd null] ifte] inscribe
1052     [gt-digits <<{} [either-or-both-null] [gt-digits.THEN] [shift-pair] tailrec] inscribe
1053
1054
1055 ### Almost Ready to Subtract
1056
1057 Now we can subtract, we just have to remember to invert the sign bit if we swap the digit lists.
1058
1059 Maybe something like:
1060
1061     check-gt == [gt-digits] [swap true] [false] ifte
1062
1063 To keep the decision around as a Boolean flag?  We can `xor` it with the sign bit?
1064
1065 Let's start with two numbers on the stack, with the same sign:
1066
1067     [bool int int int] [bool int int int]
1068
1069 Then we keep one of the sign Booleans around and discard the other:
1070
1071     [bool int int int] [bool int int int] [uncons] dip rest
1072     [bool int int int] uncons [bool int int int] rest
1073     bool [int int int] [bool int int int] rest
1074     bool [int int int] [int int int]
1075
1076 So what we really want to do is `swap` and `not`:
1077
1078     check-gt == [gt-digits] [swap [not] dipd] [] ifte
1079
1080 ### ≡ `extract-sign`
1081
1082     [extract-sign [uncons] dip rest] inscribe
1083
1084 ### ≡ `check-gt`
1085
1086     [check-gt [gt-bignum] [swap [not] dipd] [] ifte] inscribe
1087
1088
1089 ### Subtraction, at last...
1090
1091 So now that we can compare digit lists to see if one is larger than the other
1092 we can subtract (inverting the sign if necessary) much like we did addition:
1093
1094     sub-bignums == [same-sign] [sub-like-bignums] [1 0 /] ifte
1095
1096     sub-like-bignums == extract-sign check-gt sub-digits cons
1097
1098     sub-digits == initial-carry sub-digits'
1099
1100     initial-carry == false rollup
1101
1102
1103         both-empty == pop swap [] [1 swons] branch
1104          one-empty == ditch-empty-list sub-carry-from-digits
1105     both-non-empty == uncons-two [sub-with-carry] dipd
1106
1107     sub-digits′ == [both-empty] [one-empty] [both-non-empty] list-combiner-genrec
1108
1109 Which would expand into:
1110
1111     sub-digits′ == [either-or-both-null]
1112                    [[both-null] [both-empty] [one-empty] ifte]
1113                    [both-non-empty]
1114                    [i cons]
1115                    genrec
1116
1117     sub-digits′ == [either-or-both-null] [[both-null] [both-empty] [ditch-empty-list sub-carry-from-digits] ifte] [uncons-two [sub-with-carry] dipd] [i cons] genrec
1118
1119
1120
1121 We just need to define the pieces.
1122
1123 ### ≡ `sub-with-carry`
1124
1125 We know we will never be subtracting a larger (absolute) number from a smaller (absolute) number (they might be equal)
1126 so the carry flag will never be true *at the end of a digit list subtraction.*
1127
1128        carry a b sub-with-carry
1129     ------------------------------
1130          (a-b-carry)  new-carry
1131
1132     [sub-with-carry.0 - swap [] [--] branch] inscribe
1133     [sub-with-carry.1 [base + base mod] [0 <] cleave] inscribe
1134     [sub-with-carry sub-with-carry.0 sub-with-carry.1] inscribe
1135
1136
1137 ### `sub-carry-from-digits`
1138
1139 Should be easy to make modeled on `add-carry-to-digits`, another very simple recursive function.
1140 The predicate, base case, and `R1` are the same:
1141
1142     carry [n ...] sub-carry-from-digits
1143     carry [n ...] [pop not] [popd] [R0] [i cons] genrec
1144
1145 That leaves the recursive branch:
1146
1147     true [n ...] R0 [sub-carry-from-digits] i cons
1148
1149 -or-
1150
1151     true [] R0 [sub-carry-from-digits] i cons
1152
1153 **Except** that this latter case should should never happen when subtracting,
1154 because we already made sure that we're only ever subtracting a number less than or equal to the, uh,
1155 number we are subtracting from.
1156
1157                    true [a ...] R0 [sub-carry-from-digits] i cons
1158     ----------------------------------------------------------------
1159      true 0 a sub-with-carry [...] [sub-carry-from-digits] i cons
1160     ------------------------------------------------------------------
1161                  (a-1) carry [...] [sub-carry-from-digits] i cons
1162
1163 It would work like this:
1164     
1165     true [a ...] R0
1166     true [a ...] 0 swap uncons [sub-with-carry] dip
1167     true 0 [a ...] uncons [sub-with-carry] dip
1168     true 0 a [...] [sub-with-carry] dip
1169     true 0 a sub-with-carry [...]
1170
1171     R0 == 0 swap uncons [sub-with-carry] dip
1172
1173 But there's a problem!  This winds up subtracting `a` from 0 rather than the other way around:
1174
1175     R0 == uncons 0 swap [sub-with-carry] dip
1176
1177 ### ≡ `sub-carry-from-digits`
1178
1179     [sub-carry-from-digits.R0 uncons 0 swap [sub-with-carry] dip] inscribe
1180     [sub-carry-from-digits [pop not] [popd] [sub-carry-from-digits.R0] [i cons] genrec] inscribe
1181
1182 Try it out:
1183
1184     joy? clear false [3 2 1] sub-carry-from-digits
1185     [3 2 1]
1186     
1187     joy? clear true [0 1] sub-carry-from-digits
1188     [9 0]
1189     
1190     joy? clear true [3 2 1] sub-carry-from-digits
1191     [2 2 1]
1192     
1193     joy? clear true [0 0 1] sub-carry-from-digits
1194     [9 9 0]
1195
1196 But what about those leading zeroes?
1197
1198 ### ≡ `cons-but-not-leading-zeroes` and `sub-carry-from-digits`
1199
1200 We could use a version of `cons` that refuses to put 0 onto an empty list?
1201
1202     [cons-but-not-leading-zeroes [[bool] ii \/ not] [popd] [cons] ifte] inscribe
1203     [sub-carry-from-digits [pop not] [popd] [sub-carry-from-digits.R0] [i cons-but-not-leading-zeroes] genrec] inscribe
1204
1205 Good enough:
1206     
1207     joy? clear true [0 1] sub-carry-from-digits
1208     [9]
1209     
1210     joy? clear true [0 0 1] sub-carry-from-digits
1211     [9 9]
1212
1213
1214
1215
1216 # ======================================================
1217
1218
1219
1220 #### `sub-carry`
1221
1222     sub-carry == pop
1223
1224
1225 ```Joy
1226 [sub-like-bignums [uncons] dip rest check-gt sub-digits cons] inscribe
1227 [sub-digits initial-carry sub-digits'] inscribe
1228 [sub-digits'
1229     [sub-carry-from-digits]
1230     [swap pop]
1231     [sub-with-carry]
1232     build-two-list-combiner
1233     genrec
1234 ] inscribe
1235 ```
1236
1237     
1238
1239
1240 ```Joy
1241 clear
1242 true [3 2 1] [6 5 4]
1243 ```
1244
1245     true [3 2 1] [6 5 4]
1246
1247
1248 ```Joy
1249 check-gt initial-carry
1250 ```
1251
1252     false false [6 5 4] [3 2 1]
1253
1254
1255 ```Joy
1256 sub-digits'
1257 ```
1258
1259     false [3 3 3]
1260
1261
1262 ```Joy
1263 clear
1264 12345 to-bignum 109 to-bignum
1265 ```
1266
1267     [true 5 4 3 2 1] [true 9 0 1]
1268
1269
1270 ```Joy
1271 sub-like-bignums
1272 ```
1273
1274     [true 6 3 2 2 1]
1275
1276
1277 ```Joy
1278 from-bignum
1279 ```
1280
1281     12236
1282
1283
1284 ```Joy
1285 clear
1286 ```
1287
1288     
1289
1290 #### `neg-bignum`
1291
1292
1293 ```Joy
1294 [neg-bignum [not] infra] inscribe
1295 ```
1296
1297     
1298
1299
1300 ```Joy
1301 123 
1302 ```
1303
1304     123
1305
1306
1307 ```Joy
1308 to-bignum neg-bignum from-bignum
1309 ```
1310
1311     -123
1312
1313
1314 ```Joy
1315 to-bignum neg-bignum from-bignum
1316 ```
1317
1318     123
1319
1320
1321 ```Joy
1322 clear
1323 [sub-bignums [same-sign] [sub-like-bignums] [neg-bignum add-like-bignums] ifte] inscribe
1324 [add-bignums [same-sign] [add-like-bignums] [neg-bignum sub-like-bignums] ifte] inscribe
1325 ```
1326
1327     
1328
1329 ## Multiplication
1330
1331
1332
1333
1334 ```Joy
1335
1336 ```
1337
1338 ## Appendix: Source Code
1339     clear
1340     [base 2147483648]
1341     [ditch-empty-list [bool] [popd] [pop] ifte]
1342     [bool-to-int [0] [1] branch]
1343     [uncons-two [uncons] ii swapd]
1344     [sandwich swap [cons] dip swoncat]
1345
1346     [digitalize [0 <=] [pop []] [base divmod swap] [i cons] genrec]
1347     [to-bignum [!-] [abs digitalize] cleave cons]
1348
1349     [prep rest 1 0 rolldown]
1350     [from-bignum′ [next-digit] step popd]
1351     [next-digit [increase-power] [accumulate-digit] clop popdd]
1352     [increase-power popop base *]
1353     [accumulate-digit rolldown * +]
1354
1355     [sign-int [first] [prep from-bignum′] cleave]
1356     [neg-if-necessary swap [neg] [] branch]
1357     [from-bignum sign-int neg-if-necessary]
1358
1359     [add-with-carry _add-with-carry0 _add-with-carry1]
1360     [_add-with-carry0 [bool-to-int] dipd + +]
1361     [_add-with-carry1 base [mod] [>=] clop]
1362
1363     [add-carry-to-digits [pop not] [popd] [actd.R0] [i cons] genrec]
1364     [actd.R0 [bool] [actd.R0.then] [actd.R0.else] ifte]
1365     [actd.R0.else popd 1 false rolldown]
1366     [actd.R0.then 0 swap uncons [add-with-carry] dip]
1367
1368     [add-digits initial-carry add-digits']
1369     [initial-carry false rollup]
1370
1371     [add-digits' [P] [THEN] [R0] [R1] genrec]
1372     [P [bool] ii & not]
1373     [THEN [P'] [THEN'] [ELSE] ifte]
1374     [R0 uncons-two [add-with-carry] dipd]
1375     [R1 i cons]
1376     [P' [bool] ii |]
1377     [THEN' ditch-empty-list add-carry-to-digits]
1378     [ELSE pop swap [] [1 swons] branch]
1379
1380     [same-sign [first] ii xor not]
1381     [add-like-bignums [uncons] dip rest add-digits cons]
1382     [add-bignums [same-sign] [add-like-bignums] [neg-bignum sub-like-bignums] ifte]
1383
1384     [build-two-list-combiner _btlc0 _btlc1 [i cons]]
1385     [_btlc0.0 [[ditch-empty-list] swoncat] dip]
1386     [_btlc0.1 [pop] swoncat]
1387     [_btlc0.3 [_btlc0.0 _btlc0.1] dip]
1388     [_btlc0.4 [uncons-two] [dipd] sandwich]
1389     [_btlc0 _btlc0.3 _btlc0.4]
1390     [_btlc1 [[ifte] ccons [P'] swons [P] swap] dip]
1391
1392     [carry [] [1 swons] branch]
1393
1394     [compare-pairs [bool not] [pop false] [[first [>=] infrst] [pop true]] [[rest] swoncat ifte] genrec]
1395     [xR1 uncons-two [unit cons swons] dipd]
1396     [xP [bool] ii & not]
1397     [BASE [bool] [popop pop true] [[pop bool] [popop pop false] [popop compare-pairs] ifte] ifte]
1398     [gt-bignum <<{} [xP] [BASE] [xR1] tailrec]
1399     [check-gt [gt-bignum] [swap [not] dipd] [] ifte]
1400
1401     [sub-carry pop]
1402
1403     [sub-carry-from-digits [pop not] [popd] [_scfd_R0] [i cons-but-not-leading-zeroes] genrec] inscribe
1404     [_scfd_R0 uncons 0 swap [sub-with-carry] dip] inscribe
1405     [cons-but-not-leading-zeroes [P'] [cons] [popd] ifte]
1406
1407     [sub-with-carry _sub-with-carry0 _sub-with-carry1]
1408     [_sub-with-carry0 rolldown bool-to-int [-] ii]
1409     [_sub-with-carry1 [base + base mod] [0 <] cleave]
1410
1411     [sub-like-bignums [uncons] dip rest check-gt sub-digits cons]
1412     [sub-digits initial-carry sub-digits']
1413
1414     enstacken [inscribe] step
1415
1416     [add-carry-to-digits]
1417     [swap carry]
1418     [add-with-carry]
1419     build-two-list-combiner
1420     [genrec] ccons ccons
1421     [add-digits'] swoncat
1422     inscribe
1423
1424     [sub-carry-from-digits]
1425     [swap sub-carry]
1426     [sub-with-carry]
1427     build-two-list-combiner
1428     [genrec] ccons ccons
1429     [sub-digits'] swoncat
1430     inscribe
1431
1432
1433 ### notes
1434
1435 So far I have three formats for Joy source:
1436
1437 - `def.txt` is a list of definitions (UTF-8), one per line, with no special marks.
1438 - `foo ≡ bar baz...` lines in the `joy.py` embedded definition text, because why not?  (Sometimes I use `==` instead of `≡` mostly because some tools can't handle the Unicode glyph.  Like converting this notebook to PDF via LaTeX just omitted them.)
1439 - `[name body] inscribe` Joy source code that literally defines new words in the dictionary at runtime.  A text of those commands can be fed to the interpreter to customize it without any special processing (like the other two formats require.)
1440
1441 So far I prefer the `def.txt` style but that makes it tricky to embed them automatically into the `joy.py` file.
1442
1443 #### Refactoring
1444
1445 We have `i cons` but that's pretty tight already, eh?
1446
1447 However, `[i cons] genrec` is an interesting combinator.  It's almost `tailrec` with that `i` combinator for the recursion, but then `cons` means it's a list-builder (an *anamorphism* if you go for that sort of thing.)
1448
1449     simple-list-builder == [i cons] genrec
1450
1451 And maybe:
1452
1453     boolii == [bool] ii
1454
1455        both? == boolii &
1456      one-of? == boolii |
1457