OSDN Git Service

Still converting syntax highlighter spec.
[joypy/Thun.git] / docs / sphinx_docs / _build / html / _sources / notebooks / Ordered_Binary_Trees.rst.txt
1 Treating Trees I: Ordered Binary Trees
2 ======================================
3
4 Although any expression in Joy can be considered to describe a
5 `tree <https://en.wikipedia.org/wiki/Tree_structure>`__ with the quotes
6 as compound nodes and the non-quote values as leaf nodes, in this page I
7 want to talk about `ordered binary
8 trees <https://en.wikipedia.org/wiki/Binary_search_tree>`__ and how to
9 make and use them.
10
11 The basic structure, in a `crude type
12 notation <https://en.wikipedia.org/wiki/Algebraic_data_type>`__, is:
13
14 ::
15
16    Tree :: [] | [key value Tree Tree]
17
18 That says that a Tree is either the empty quote ``[]`` or a quote with
19 four items: a key, a value, and two Trees representing the left and
20 right branches of the tree.
21
22 We’re going to derive some recursive functions to work with such
23 datastructures:
24
25 ::
26
27    Tree-add
28    Tree-delete
29    Tree-get
30    Tree-iter
31    Tree-iter-order
32
33 Once these functions are defined we have a new “type” to work with, and
34 the Sufficiently Smart Compiler can be modified to use an optimized
35 implementation under the hood. (Where does the “type” come from? It has
36 a contingent existence predicated on the disciplined use of these
37 functions on otherwise undistinguished Joy datastructures.)
38
39 .. code:: python
40
41     from notebook_preamble import D, J, V, define, DefinitionWrapper
42
43 Adding Nodes to the Tree
44 ------------------------
45
46 Let’s consider adding nodes to a Tree structure.
47
48 ::
49
50       Tree value key Tree-add
51    -----------------------------
52                Tree′
53
54 Adding to an empty node.
55 ~~~~~~~~~~~~~~~~~~~~~~~~
56
57 If the current node is ``[]`` then you just return
58 ``[key value [] []]``:
59
60 ::
61
62    Tree-add == [popop not] [[pop] dipd Tree-new] [R0] [R1] genrec
63
64 ``Tree-new``
65 ^^^^^^^^^^^^
66
67 Where ``Tree-new`` is defined as:
68
69 ::
70
71       value key Tree-new
72    ------------------------
73       [key value [] []]
74
75 Example:
76
77 ::
78
79    value key swap [[] []] cons cons
80    key value      [[] []] cons cons
81    key      [value [] []]      cons
82         [key value [] []]
83
84 Definition:
85
86 ::
87
88    Tree-new == swap [[] []] cons cons
89
90 .. code:: python
91
92     define('Tree-new == swap [[] []] cons cons')
93
94 .. code:: python
95
96     J('"v" "k" Tree-new')
97
98
99 .. parsed-literal::
100
101     ['k' 'v' [] []]
102
103
104 (As an implementation detail, the ``[[] []]`` literal used in the
105 definition of ``Tree-new`` will be reused to supply the *constant* tail
106 for *all* new nodes produced by it. This is one of those cases where you
107 get amortized storage “for free” by using `persistent
108 datastructures <https://en.wikipedia.org/wiki/Persistent_data_structure>`__.
109 Because the tail, which is ``((), ((), ()))`` in Python, is immutable
110 and embedded in the definition body for ``Tree-new``, all new nodes can
111 reuse it as their own tail without fear that some other code somewhere
112 will change it.)
113
114 Adding to a non-empty node.
115 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
116
117 We now have to derive ``R0`` and ``R1``, consider:
118
119 ::
120
121    [key_n value_n left right] value key R0 [Tree-add] R1
122
123 In this case, there are three possibilites: the key can be greater or
124 less than or equal to the node’s key. In two of those cases we will need
125 to apply a copy of ``Tree-add``, so ``R0`` is pretty much out of the
126 picture.
127
128 ::
129
130    [R0] == []
131
132 A predicate to compare keys.
133 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
134
135 ::
136
137    [key_n value_n left right] value key [BTree-add] R1
138
139 The first thing we need to do is compare the the key we’re adding to the
140 node key and ``branch`` accordingly:
141
142 ::
143
144    [key_n value_n left right] value key [BTree-add] [P] [T] [E] ifte
145
146 That would suggest something like:
147
148 ::
149
150    [key_n value_n left right] value key [BTree-add] P
151    [key_n value_n left right] value key [BTree-add] pop roll> pop first >
152    [key_n value_n left right] value key                 roll> pop first >
153    key [key_n value_n left right] value                 roll> pop first >
154    key key_n                                                            >
155    Boolean
156
157 Let’s abstract the predicate just a little to let us specify the
158 comparison operator:
159
160 ::
161
162    P > == pop roll> pop first >
163    P < == pop roll> pop first <
164    P   == pop roll> pop first
165
166 .. code:: python
167
168     define('P == pop roll> pop first')
169
170 .. code:: python
171
172     J('["old_key" 23 [] []] 17 "new_key" ["..."] P')
173
174
175 .. parsed-literal::
176
177     'new_key' 'old_key'
178
179
180 If the key we’re adding is greater than the node’s key.
181 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
182
183 Here the parentheses are meant to signify that the expression is not
184 literal, the code in the parentheses is meant to have been evaluated:
185
186 ::
187
188       [key_n value_n left right] value key [Tree-add] T
189    -------------------------------------------------------
190       [key_n value_n left (Tree-add key value right)]
191
192 So how do we do this? We’re going to want to use ``infra`` on some
193 function ``K`` that has the key and value to work with, as well as the
194 quoted copy of ``Tree-add`` to apply somehow. Considering the node as a
195 stack:
196
197 ::
198
199       right left value_n key_n value key [Tree-add] K
200    -----------------------------------------------------
201       right value key Tree-add left value_n key_n
202
203 Pretty easy:
204
205 ::
206
207    right left value_n key_n value key [Tree-add] cons cons dipdd
208    right left value_n key_n [value key Tree-add]           dipdd
209    right value key Tree-add left value_n key_n
210
211 So:
212
213 ::
214
215    K == cons cons dipdd
216
217 Looking at it from the point-of-view of the node as node again:
218
219 ::
220
221    [key_n value_n left right] [value key [Tree-add] K] infra
222
223 Expand ``K`` and evaluate a little:
224
225 ::
226
227    [key_n value_n left right] [value key [Tree-add] K] infra
228    [key_n value_n left right] [value key [Tree-add] cons cons dipdd] infra
229    [key_n value_n left right] [[value key Tree-add]           dipdd] infra
230
231 Then, working backwards:
232
233 ::
234
235    [key_n value_n left right] [[value key Tree-add]           dipdd]      infra
236    [key_n value_n left right] [value key Tree-add]           [dipdd] cons infra
237    [key_n value_n left right] value key [Tree-add] cons cons [dipdd] cons infra
238
239 And so ``T`` is just:
240
241 ::
242
243    T == cons cons [dipdd] cons infra
244
245 .. code:: python
246
247     define('T == cons cons [dipdd] cons infra')
248
249 .. code:: python
250
251     J('["old_k" "old_value" "left" "right"] "new_value" "new_key" ["Tree-add"] T')
252
253
254 .. parsed-literal::
255
256     ['old_k' 'old_value' 'left' 'Tree-add' 'new_key' 'new_value' 'right']
257
258
259 If the key we’re adding is less than the node’s key.
260 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
261
262 This is very very similar to the above:
263
264 ::
265
266    [key_n value_n left right] value key [Tree-add] E
267    [key_n value_n left right] value key [Tree-add] [P <] [Te] [Ee] ifte
268
269 .. code:: python
270
271     define('E == [P <] [Te] [Ee] ifte')
272
273 In this case ``Te`` works that same as ``T`` but on the left child tree
274 instead of the right, so the only difference is that it must use
275 ``dipd`` instead of ``dipdd``:
276
277 ::
278
279    Te == cons cons [dipd] cons infra
280
281 .. code:: python
282
283     define('Te == cons cons [dipd] cons infra')
284
285 .. code:: python
286
287     J('["old_k" "old_value" "left" "right"] "new_value" "new_key" ["Tree-add"] Te')
288
289
290 .. parsed-literal::
291
292     ['old_k' 'old_value' 'Tree-add' 'new_key' 'new_value' 'left' 'right']
293
294
295 Else the keys must be equal.
296 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
297
298 This means we must find:
299
300 ::
301
302       [key old_value left right] new_value key [Tree-add] Ee
303    ------------------------------------------------------------
304       [key new_value left right]
305
306 This is another easy one:
307
308 ::
309
310    Ee == pop swap roll< rest rest cons cons
311
312 Example:
313
314 ::
315
316    [key old_value left right] new_value key [Tree-add] pop swap roll< rest rest cons cons
317    [key old_value left right] new_value key                swap roll< rest rest cons cons
318    [key old_value left right] key new_value                     roll< rest rest cons cons
319    key new_value [key old_value left right]                           rest rest cons cons
320    key new_value [              left right]                                     cons cons
321                  [key new_value left right]
322
323 .. code:: python
324
325     define('Ee == pop swap roll< rest rest cons cons')
326
327 .. code:: python
328
329     J('["k" "old_value" "left" "right"] "new_value" "k" ["Tree-add"] Ee')
330
331
332 .. parsed-literal::
333
334     ['k' 'new_value' 'left' 'right']
335
336
337 Now we can define ``Tree-add``
338 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
339
340 ::
341
342    Tree-add == [popop not] [[pop] dipd Tree-new] [] [[P >] [T] [E] ifte] genrec
343
344 Putting it all together:
345
346 ::
347
348    Tree-new == swap [[] []] cons cons
349    P == pop roll> pop first
350    T == cons cons [dipdd] cons infra
351    Te == cons cons [dipd] cons infra
352    Ee == pop swap roll< rest rest cons cons
353    E == [P <] [Te] [Ee] ifte
354    R == [P >] [T] [E] ifte
355
356    Tree-add == [popop not] [[pop] dipd Tree-new] [] [R] genrec
357
358 .. code:: python
359
360     define('Tree-add == [popop not] [[pop] dipd Tree-new] [] [[P >] [T] [E] ifte] genrec')
361
362 Examples
363 ~~~~~~~~
364
365 .. code:: python
366
367     J('[] 23 "b" Tree-add')  # Initial
368
369
370 .. parsed-literal::
371
372     ['b' 23 [] []]
373
374
375 .. code:: python
376
377     J('["b" 23 [] []] 88 "c" Tree-add')  # Greater than
378
379
380 .. parsed-literal::
381
382     ['b' 23 [] ['c' 88 [] []]]
383
384
385 .. code:: python
386
387     J('["b" 23 [] []] 88 "a" Tree-add')  # Less than
388
389
390 .. parsed-literal::
391
392     ['b' 23 ['a' 88 [] []] []]
393
394
395 .. code:: python
396
397     J('["b" 23 [] []] 88 "b" Tree-add')  # Equal to
398
399
400 .. parsed-literal::
401
402     ['b' 88 [] []]
403
404
405 .. code:: python
406
407     J('[] 23 "b" Tree-add 88 "a" Tree-add 44 "c" Tree-add')  # Series.
408
409
410 .. parsed-literal::
411
412     ['b' 23 ['a' 88 [] []] ['c' 44 [] []]]
413
414
415 .. code:: python
416
417     J('[] [[23 "b"] [88 "a"] [44 "c"]] [i Tree-add] step')
418
419
420 .. parsed-literal::
421
422     ['b' 23 ['a' 88 [] []] ['c' 44 [] []]]
423
424
425 Interlude: ``cmp`` combinator
426 -----------------------------
427
428 Instead of mucking about with nested ``ifte`` combinators let’s use
429 ``cmp`` which takes two values and three quoted programs on the stack
430 and runs one of the three depending on the results of comparing the two
431 values:
432
433 ::
434
435       a b [G] [E] [L] cmp
436    ------------------------- a > b
437            G
438
439       a b [G] [E] [L] cmp
440    ------------------------- a = b
441                E
442
443       a b [G] [E] [L] cmp
444    ------------------------- a < b
445                    L
446
447 .. code:: python
448
449     J("1 0 ['G'] ['E'] ['L'] cmp")
450
451
452 .. parsed-literal::
453
454     'G'
455
456
457 .. code:: python
458
459     J("1 1 ['G'] ['E'] ['L'] cmp")
460
461
462 .. parsed-literal::
463
464     'E'
465
466
467 .. code:: python
468
469     J("0 1 ['G'] ['E'] ['L'] cmp")
470
471
472 .. parsed-literal::
473
474     'L'
475
476
477 Redefine ``Tree-add``
478 ~~~~~~~~~~~~~~~~~~~~~
479
480 We need a new non-destructive predicate ``P``:
481
482 ::
483
484       [node_key node_value left right] value key [Tree-add] P
485    ------------------------------------------------------------------------
486       [node_key node_value left right] value key [Tree-add] key node_key
487
488 Let’s start with ``over`` to get a copy of the key and then apply some
489 function ``Q`` with the ``nullary`` combinator so it can dig out the
490 node key (by throwing everything else away):
491
492 ::
493
494    P == over [Q] nullary
495
496    [node_key node_value left right] value key [Tree-add] over [Q] nullary
497    [node_key node_value left right] value key [Tree-add] key  [Q] nullary
498
499 And ``Q`` would be:
500
501 ::
502
503    Q == popop popop first
504
505    [node_key node_value left right] value key [Tree-add] key Q
506    [node_key node_value left right] value key [Tree-add] key popop popop first
507    [node_key node_value left right] value key                      popop first
508    [node_key node_value left right]                                      first
509     node_key
510
511 Or just:
512
513 ::
514
515    P == over [popop popop first] nullary
516
517 .. code:: python
518
519     define('P == over [popop popop first] nullary')
520
521 Using ``cmp`` to simplify `our code above at
522 ``R1`` <#Adding-to-a-non-empty-node.>`__:
523
524 ::
525
526    [node_key node_value left right] value key [Tree-add] R1
527    [node_key node_value left right] value key [Tree-add] P [T] [E] [Te] cmp
528
529 The line above becomes one of the three lines below:
530
531 ::
532
533    [node_key node_value left right] value key [Tree-add] T
534    [node_key node_value left right] value key [Tree-add] E
535    [node_key node_value left right] value key [Tree-add] Te
536
537 The definition is a little longer but, I think, more elegant and easier
538 to understand:
539
540 ::
541
542    Tree-add == [popop not] [[pop] dipd Tree-new] [] [P [T] [Ee] [Te] cmp] genrec
543
544 .. code:: python
545
546     define('Tree-add == [popop not] [[pop] dipd Tree-new] [] [P [T] [Ee] [Te] cmp] genrec')
547
548 .. code:: python
549
550     J('[] 23 "b" Tree-add 88 "a" Tree-add 44 "c" Tree-add')  # Still works.
551
552
553 .. parsed-literal::
554
555     ['b' 23 ['a' 88 [] []] ['c' 44 [] []]]
556
557
558 A Function to Traverse this Structure
559 -------------------------------------
560
561 Let’s take a crack at writing a function that can recursively iterate or
562 traverse these trees.
563
564 Base case ``[]``
565 ~~~~~~~~~~~~~~~~
566
567 The stopping predicate just has to detect the empty list:
568
569 ::
570
571    Tree-iter == [not] [E] [R0] [R1] genrec
572
573 And since there’s nothing at this node, we just ``pop`` it:
574
575 ::
576
577    Tree-iter == [not] [pop] [R0] [R1] genrec
578
579 Node case ``[key value left right]``
580 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
581
582 Now we need to figure out ``R0`` and ``R1``:
583
584 ::
585
586    Tree-iter == [not] [pop] [R0]           [R1] genrec
587              == [not] [pop] [R0 [Tree-iter] R1] ifte
588
589 Let’s look at it *in situ*:
590
591 ::
592
593    [key value left right] R0 [Tree-iter] R1
594
595 Processing the current node.
596 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
597
598 ``R0`` is almost certainly going to use ``dup`` to make a copy of the
599 node and then ``dip`` on some function to process the copy with it:
600
601 ::
602
603    [key value left right] [F] dupdip                 [Tree-iter] R1
604    [key value left right]  F  [key value left right] [Tree-iter] R1
605
606 For example, if we’re getting all the keys ``F`` would be ``first``:
607
608 ::
609
610    R0 == [first] dupdip
611
612    [key value left right] [first] dupdip                 [Tree-iter] R1
613    [key value left right]  first  [key value left right] [Tree-iter] R1
614    key                            [key value left right] [Tree-iter] R1
615
616 Recur
617 ^^^^^
618
619 Now ``R1`` needs to apply ``[Tree-iter]`` to ``left`` and ``right``. If
620 we drop the key and value from the node using ``rest`` twice we are left
621 with an interesting situation:
622
623 ::
624
625    key [key value left right] [Tree-iter] R1
626    key [key value left right] [Tree-iter] [rest rest] dip
627    key [key value left right] rest rest [Tree-iter]
628    key [left right] [Tree-iter]
629
630 Hmm, will ``step`` do?
631
632 ::
633
634    key [left right] [Tree-iter] step
635    key left Tree-iter [right] [Tree-iter] step
636    key left-keys [right] [Tree-iter] step
637    key left-keys right Tree-iter
638    key left-keys right-keys
639
640 Neat. So:
641
642 ::
643
644    R1 == [rest rest] dip step
645
646 Putting it together
647 ~~~~~~~~~~~~~~~~~~~
648
649 We have:
650
651 ::
652
653    Tree-iter == [not] [pop] [[F] dupdip] [[rest rest] dip step] genrec
654
655 When I was reading this over I realized ``rest rest`` could go in
656 ``R0``:
657
658 ::
659
660    Tree-iter == [not] [pop] [[F] dupdip rest rest] [step] genrec
661
662 (And ``[step] genrec`` is such a cool and suggestive combinator!)
663
664 Parameterizing the ``F`` per-node processing function.
665 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
666
667 ::
668
669                    [F] Tree-iter
670    ------------------------------------------------------
671       [not] [pop] [[F] dupdip rest rest] [step] genrec
672
673 Working backward:
674
675 ::
676
677    [not] [pop] [[F] dupdip rest rest]            [step] genrec
678    [not] [pop] [F]       [dupdip rest rest] cons [step] genrec
679    [F] [not] [pop] roll< [dupdip rest rest] cons [step] genrec
680
681 ``Tree-iter``
682 ~~~~~~~~~~~~~
683
684 ::
685
686    Tree-iter == [not] [pop] roll< [dupdip rest rest] cons [step] genrec
687
688 .. code:: python
689
690     define('Tree-iter == [not] [pop] roll< [dupdip rest rest] cons [step] genrec')
691
692 Examples
693 ~~~~~~~~
694
695 .. code:: python
696
697     J('[] [foo] Tree-iter')  #  It doesn't matter what F is as it won't be used.
698
699
700 .. parsed-literal::
701
702     
703
704
705 .. code:: python
706
707     J("['b' 23 ['a' 88 [] []] ['c' 44 [] []]] [first] Tree-iter")
708
709
710 .. parsed-literal::
711
712     'b' 'a' 'c'
713
714
715 .. code:: python
716
717     J("['b' 23 ['a' 88 [] []] ['c' 44 [] []]] [second] Tree-iter")
718
719
720 .. parsed-literal::
721
722     23 88 44
723
724
725 Interlude: A Set-like Datastructure
726 -----------------------------------
727
728 We can use this to make a set-like datastructure by just setting values
729 to e.g. 0 and ignoring them. It’s set-like in that duplicate items added
730 to it will only occur once within it, and we can query it in
731 `:math:`O(\log_2 N)` <https://en.wikipedia.org/wiki/Binary_search_tree#cite_note-2>`__
732 time.
733
734 .. code:: python
735
736     J('[] [3 9 5 2 8 6 7 8 4] [0 swap Tree-add] step')
737
738
739 .. parsed-literal::
740
741     [3 0 [2 0 [] []] [9 0 [5 0 [4 0 [] []] [8 0 [6 0 [] [7 0 [] []]] []]] []]]
742
743
744 .. code:: python
745
746     define('to_set == [] swap [0 swap Tree-add] step')
747
748 .. code:: python
749
750     J('[3 9 5 2 8 6 7 8 4] to_set')
751
752
753 .. parsed-literal::
754
755     [3 0 [2 0 [] []] [9 0 [5 0 [4 0 [] []] [8 0 [6 0 [] [7 0 [] []]] []]] []]]
756
757
758 And with that we can write a little program ``unique`` to remove
759 duplicate items from a list.
760
761 .. code:: python
762
763     define('unique == [to_set [first] Tree-iter] cons run')
764
765 .. code:: python
766
767     J('[3 9 3 5 2 9 8 8 8 6 2 7 8 4 3] unique')  # Filter duplicate items.
768
769
770 .. parsed-literal::
771
772     [7 6 8 4 5 9 2 3]
773
774
775 A Version of ``Tree-iter`` that does In-Order Traversal
776 -------------------------------------------------------
777
778 If you look back to the `non-empty case of the ``Tree-iter``
779 function <#Node-case-%5Bkey-value-left-right%5D>`__ we can design a
780 variant that first processes the left child, then the current node, then
781 the right child. This will allow us to traverse the tree in sort order.
782
783 ::
784
785    Tree-iter-order == [not] [pop] [R0] [R1] genrec
786
787 To define ``R0`` and ``R1`` it helps to look at them as they will appear
788 when they run:
789
790 ::
791
792    [key value left right] R0 [BTree-iter-order] R1
793
794 Process the left child.
795 ~~~~~~~~~~~~~~~~~~~~~~~
796
797 Staring at this for a bit suggests ``dup third`` to start:
798
799 ::
800
801    [key value left right] R0        [Tree-iter-order] R1
802    [key value left right] dup third [Tree-iter-order] R1
803    [key value left right] left      [Tree-iter-order] R1
804
805 Now maybe:
806
807 ::
808
809    [key value left right] left [Tree-iter-order] [cons dip] dupdip
810    [key value left right] left [Tree-iter-order]  cons dip [Tree-iter-order]
811    [key value left right] [left Tree-iter-order]       dip [Tree-iter-order]
812    left Tree-iter-order [key value left right]             [Tree-iter-order]
813
814 Process the current node.
815 ~~~~~~~~~~~~~~~~~~~~~~~~~
816
817 So far, so good. Now we need to process the current node’s values:
818
819 ::
820
821    left Tree-iter-order [key value left right] [Tree-iter-order] [[F] dupdip] dip
822    left Tree-iter-order [key value left right] [F] dupdip [Tree-iter-order]
823    left Tree-iter-order [key value left right] F [key value left right] [Tree-iter-order]
824
825 If ``F`` needs items from the stack below the left stuff it should have
826 ``cons``\ ’d them before beginning maybe? For functions like ``first``
827 it works fine as-is.
828
829 ::
830
831    left Tree-iter-order [key value left right] first [key value left right] [Tree-iter-order]
832    left Tree-iter-order key [key value left right] [Tree-iter-order]
833
834 Process the right child.
835 ~~~~~~~~~~~~~~~~~~~~~~~~
836
837 First ditch the rest of the node and get the right child:
838
839 ::
840
841    left Tree-iter-order key [key value left right] [Tree-iter-order] [rest rest rest first] dip
842    left Tree-iter-order key right [Tree-iter-order]
843
844 Then, of course, we just need ``i`` to run ``Tree-iter-order`` on the
845 right side:
846
847 ::
848
849    left Tree-iter-order key right [Tree-iter-order] i
850    left Tree-iter-order key right Tree-iter-order
851
852 Defining ``Tree-iter-order``
853 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
854
855 The result is a little awkward:
856
857 ::
858
859    R1 == [cons dip] dupdip [[F] dupdip] dip [rest rest rest first] dip i
860
861 Let’s do a little semantic factoring:
862
863 ::
864
865    fourth == rest rest rest first
866
867    proc_left == [cons dip] dupdip
868    proc_current == [[F] dupdip] dip
869    proc_right == [fourth] dip i
870
871    Tree-iter-order == [not] [pop] [dup third] [proc_left proc_current proc_right] genrec
872
873 Now we can sort sequences.
874
875 .. code:: python
876
877     #define('Tree-iter-order == [not] [pop] [dup third] [[cons dip] dupdip [[first] dupdip] dip [rest rest rest first] dip i] genrec')
878     
879     
880     DefinitionWrapper.add_definitions('''
881     
882     fourth == rest rest rest first
883     
884     proc_left == [cons dip] dupdip
885     proc_current == [[first] dupdip] dip
886     proc_right == [fourth] dip i
887     
888     Tree-iter-order == [not] [pop] [dup third] [proc_left proc_current proc_right] genrec
889     
890     ''', D)
891     
892     
893
894
895 .. code:: python
896
897     J('[3 9 5 2 8 6 7 8 4] to_set Tree-iter-order')
898
899
900 .. parsed-literal::
901
902     2 3 4 5 6 7 8 9
903
904
905 Parameterizing the ``[F]`` function is left as an exercise for the
906 reader.
907
908 Getting values by key
909 ---------------------
910
911 Let’s derive a function that accepts a tree and a key and returns the
912 value associated with that key.
913
914 ::
915
916       tree key Tree-get
917    -----------------------
918            value
919
920 But what do we do if the key isn’t in the tree? In Python we might raise
921 a ``KeyError`` but I’d like to avoid exceptions in Joy if possible, and
922 here I think it’s possible. (Division by zero is an example of where I
923 think it’s probably better to let Python crash Joy. Sometimes the
924 machinery fails and you have to “stop the line”, I think.)
925
926 Let’s pass the buck to the caller by making the base case a given, you
927 have to decide for yourself what ``[E]`` should be.
928
929 ::
930
931       tree key [E] Tree-get
932    ---------------------------- key in tree
933               value
934
935       tree key [E] Tree-get
936    ---------------------------- key not in tree
937             [] key E
938
939 The base case ``[]``
940 ~~~~~~~~~~~~~~~~~~~~
941
942 As before, the stopping predicate just has to detect the empty list:
943
944 ::
945
946    Tree-get == [pop not] [E] [R0] [R1] genrec
947
948 So we define:
949
950 ::
951
952    Tree-get == [pop not] swap [R0] [R1] genrec
953
954 Note that this ``Tree-get`` creates a slightly different function than
955 itself and *that function* does the actual recursion. This kind of
956 higher-level programming is unusual in most languages but natural in
957 Joy.
958
959 ::
960
961    tree key [E] [pop not] swap [R0] [R1] genrec
962    tree key [pop not] [E] [R0] [R1] genrec
963
964 The anonymous specialized recursive function that will do the real work.
965
966 ::
967
968    [pop not] [E] [R0] [R1] genrec
969
970 Node case ``[key value left right]``
971 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
972
973 Now we need to figure out ``R0`` and ``R1``:
974
975 ::
976
977    [key value left right] key R0 [BTree-get] R1
978
979 We want to compare the search key with the key in the node, and if they
980 are the same return the value, otherwise recur on one of the child
981 nodes. So it’s very similar to the above funtion, with ``[R0] == []``
982 and ``R1 == P [T>] [E] [T<] cmp``:
983
984 ::
985
986    [key value left right] key [BTree-get] P [T>] [E] [T<] cmp
987
988 Predicate
989 ^^^^^^^^^
990
991 ::
992
993    P == over [get-node-key] nullary
994    get-node-key == pop popop first
995
996 The only difference is that ``get-node-key`` does one less ``pop``
997 because there’s no value to discard.
998
999 Branches
1000 ^^^^^^^^
1001
1002 Now we have to derive the branches:
1003
1004 ::
1005
1006    [key_n value_n left right] key [BTree-get] T>
1007    [key_n value_n left right] key [BTree-get] E
1008    [key_n value_n left right] key [BTree-get] T<
1009
1010 Greater than and less than
1011 ^^^^^^^^^^^^^^^^^^^^^^^^^^
1012
1013 The cases of ``T>`` and ``T<`` are similar to above but instead of using
1014 ``infra`` we have to discard the rest of the structure:
1015
1016 ::
1017
1018       [key_n value_n left right] key [BTree-get] T>
1019    ---------------------------------------------------
1020                           right  key  BTree-get
1021
1022 And:
1023
1024 ::
1025
1026       [key_n value_n left right] key [BTree-get] T<
1027    ---------------------------------------------------
1028                      left        key  BTree-get
1029
1030 So:
1031
1032 ::
1033
1034    T> == [fourth] dipd i
1035    T< == [third] dipd i
1036
1037 E.g.:
1038
1039 ::
1040
1041    [key_n value_n left right]        key [BTree-get] [fourth] dipd i
1042    [key_n value_n left right] fourth key [BTree-get]               i
1043                        right         key [BTree-get]               i
1044                        right         key  BTree-get
1045
1046 Equal keys
1047 ^^^^^^^^^^
1048
1049 Return the node’s value:
1050
1051 ::
1052
1053    [key_n value_n left right] key [BTree-get] E == value_n
1054
1055    E == popop second
1056
1057 ``Tree-get``
1058 ~~~~~~~~~~~~
1059
1060 So:
1061
1062 ::
1063
1064    fourth == rest rest rest first
1065    get-node-key == pop popop first
1066    P == over [get-node-key] nullary
1067    T> == [fourth] dipd i
1068    T< == [third] dipd i
1069    E == popop second
1070
1071    Tree-get == [pop not] swap [] [P [T>] [E] [T<] cmp] genrec
1072
1073 .. code:: python
1074
1075     # I don't want to deal with name conflicts with the above so I'm inlining everything here.
1076     # The original Joy system has "hide" which is a meta-command which allows you to use named
1077     # definitions that are only in scope for a given definition.  I don't want to implement
1078     # that (yet) so...
1079     
1080     
1081     define('''
1082     Tree-get == [pop not] swap [] [
1083       over [pop popop first] nullary
1084       [[fourth] dipd i]
1085       [popop second]
1086       [[third] dipd i]
1087       cmp
1088       ] genrec
1089     ''')
1090
1091 .. code:: python
1092
1093     J('["gary" 23 [] []] "mike" [popd " not in tree" +] Tree-get')
1094
1095
1096 .. parsed-literal::
1097
1098     'mike not in tree'
1099
1100
1101 .. code:: python
1102
1103     J('["gary" 23 [] []] "gary" [popop "err"] Tree-get')
1104
1105
1106 .. parsed-literal::
1107
1108     23
1109
1110
1111 .. code:: python
1112
1113     J('''
1114     
1115         [] [[0 'a'] [1 'b'] [2 'c']] [i Tree-add] step
1116     
1117         'c' [popop 'not found'] Tree-get
1118     
1119     ''')
1120
1121
1122 .. parsed-literal::
1123
1124     2
1125
1126
1127 .. code:: python
1128
1129     J('''
1130     
1131         [] [[0 'a'] [1 'b'] [2 'c']] [i Tree-add] step
1132     
1133         'd' [popop 'not found'] Tree-get
1134     
1135     ''')
1136
1137
1138 .. parsed-literal::
1139
1140     'not found'
1141
1142
1143 Tree-delete
1144 -----------
1145
1146 Now let’s write a function that can return a tree datastructure with a
1147 key, value pair deleted:
1148
1149 ::
1150
1151       tree key Tree-delete
1152    ---------------------------
1153              tree
1154
1155 If the key is not in tree it just returns the tree unchanged.
1156
1157 Base case
1158 ~~~~~~~~~
1159
1160 Same as above.
1161
1162 ::
1163
1164    Tree-Delete == [pop not] [pop] [R0] [R1] genrec
1165
1166 Recur
1167 ~~~~~
1168
1169 Now we get to figure out the recursive case. We need the node’s key to
1170 compare and we need to carry the key into recursive branches. Let ``D``
1171 be shorthand for ``Tree-Delete``:
1172
1173 ::
1174
1175    D == Tree-Delete == [pop not] [pop] [R0] [R1] genrec
1176
1177    [node_key node_value left right] key R0                   [D] R1
1178    [node_key node_value left right] key over  first swap dup [D] cons R1′
1179    [node_key node_value left right] key [...] first swap dup [D] cons R1′
1180    [node_key node_value left right] key node_key    swap dup [D] cons R1′
1181    [node_key node_value left right] node_key key         dup [D] cons R1′
1182    [node_key node_value left right] node_key key key         [D] cons R1′
1183    [node_key node_value left right] node_key key         [key D]      R1′
1184
1185 And then:
1186
1187 ::
1188
1189    [node_key node_value left right] node_key key [key D] R1′
1190    [node_key node_value left right] node_key key [key D] roll> [T>] [E] [T<] cmp
1191    [node_key node_value left right] node_key key [key D] roll> [T>] [E] [T<] cmp
1192    [node_key node_value left right] [key D] node_key key       [T>] [E] [T<] cmp
1193
1194 So:
1195
1196 ::
1197
1198    R0 == over first swap dup
1199    R1 == cons roll> [T>] [E] [T<] cmp
1200
1201 Compare Keys
1202 ~~~~~~~~~~~~
1203
1204 The last line above:
1205
1206 ::
1207
1208    [node_key node_value left right] [key D] node_key key [T>] [E] [T<] cmp
1209
1210 Then becomes one of these three:
1211
1212 ::
1213
1214    [node_key node_value left right] [key D] T>
1215    [node_key node_value left right] [key D] E
1216    [node_key node_value left right] [key D] T<
1217
1218 Greater than case and less than case
1219 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1220
1221 ::
1222
1223       [node_key node_value left right] [F] T>
1224    -------------------------------------------------
1225       [node_key node_value (left F) right]
1226
1227
1228       [node_key node_value left right] [F] T<
1229    -------------------------------------------------
1230       [node_key node_value left (right F)]
1231
1232 First, treating the node as a stack:
1233
1234 ::
1235
1236    right left       node_value node_key [key D] dipd
1237    right left key D node_value node_key
1238    right left'      node_value node_key
1239
1240 Ergo:
1241
1242 ::
1243
1244    [node_key node_value left right] [key D] [dipd] cons infra
1245
1246 So:
1247
1248 ::
1249
1250    T> == [dipd] cons infra
1251    T< == [dipdd] cons infra
1252
1253 The else case
1254 ~~~~~~~~~~~~~
1255
1256 We have found the node in the tree where ``key`` equals ``node_key``. We
1257 need to replace the current node with something
1258
1259 ::
1260
1261       [node_key node_value left right] [key D] E
1262    ------------------------------------------------
1263                        tree
1264
1265 We have to handle three cases, so let’s use ``cond``.
1266
1267 One or more child nodes are ``[]``
1268 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1269
1270 The first two cases are symmetrical: if we only have one non-empty child
1271 node return it. If both child nodes are empty return an empty node.
1272
1273 ::
1274
1275    E == [
1276        [[pop third not] pop fourth]
1277        [[pop fourth not] pop third]
1278        [default]
1279    ] cond
1280
1281 Both child nodes are non-empty.
1282 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1283
1284 If both child nodes are non-empty, we find the highest node in our lower
1285 sub-tree, take its key and value to replace (delete) our own, then get
1286 rid of it by recursively calling delete() on our lower sub-node with our
1287 new key.
1288
1289 (We could also find the lowest node in our higher sub-tree and take its
1290 key and value and delete it. I only implemented one of these two
1291 symmetrical options. Over a lot of deletions this might make the tree
1292 more unbalanced. Oh well.)
1293
1294 The initial structure of the default function:
1295
1296 ::
1297
1298    default == [E′] cons infra
1299
1300    [node_key node_value left right] [key D] default
1301    [node_key node_value left right] [key D] [E′] cons infra
1302    [node_key node_value left right] [[key D] E′]      infra
1303
1304    right left node_value node_key [key D] E′
1305
1306 First things first, we no longer need this node’s key and value:
1307
1308 ::
1309
1310    right left node_value node_key [key D] roll> popop E″
1311    right left [key D] node_value node_key       popop E″
1312    right left [key D]                                 E″
1313
1314 We have to we find the highest (right-most) node in our lower (left) sub-tree:
1315 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1316
1317 ::
1318
1319    right left [key D] E″
1320
1321 Ditch the key:
1322
1323 ::
1324
1325    right left [key D] rest E‴
1326    right left     [D]      E‴
1327
1328 Find the right-most node:
1329
1330 ::
1331
1332    right left        [D] [dup W] dip E⁗
1333    right left dup  W [D]             E⁗
1334    right left left W [D]             E⁗
1335
1336 Consider:
1337
1338 ::
1339
1340    left W
1341
1342 We know left is not empty:
1343
1344 ::
1345
1346    [L_key L_value L_left L_right] W
1347
1348 We want to keep extracting the right node as long as it is not empty:
1349
1350 ::
1351
1352    W.rightmost == [P] [B] while
1353
1354    left W.rightmost W′
1355
1356 The predicate:
1357
1358 ::
1359
1360    [L_key L_value L_left L_right] P
1361    [L_key L_value L_left L_right] fourth
1362                          L_right
1363
1364 This can run on ``[]`` so must be guarded:
1365
1366 ::
1367
1368    ?fourth ==  [] [fourth] [] ifte
1369
1370 ( if_not_empty == [] swap [] ifte ?fourth == [fourth] if_not_empty )
1371
1372 The body is just ``fourth``:
1373
1374 ::
1375
1376    left [?fourth] [fourth] while W′
1377    rightest                      W′
1378
1379 So:
1380
1381 ::
1382
1383    W.rightmost == [?fourth] [fourth] while
1384
1385 Found right-most node in our left sub-tree
1386 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1387
1388 We know rightest is not empty:
1389
1390 ::
1391
1392    [R_key R_value R_left R_right] W′
1393    [R_key R_value R_left R_right] W′
1394    [R_key R_value R_left R_right] uncons uncons pop
1395    R_key [R_value R_left R_right]        uncons pop
1396    R_key R_value [R_left R_right]               pop
1397    R_key R_value
1398
1399 So:
1400
1401 ::
1402
1403    W == [?fourth] [fourth] while uncons uncons pop
1404
1405 And:
1406
1407 ::
1408
1409    right left left W        [D] E⁗
1410    right left R_key R_value [D] E⁗
1411
1412 Replace current node key and value, recursively delete rightmost
1413 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1414
1415 Final stretch. We want to end up with something like:
1416
1417 ::
1418
1419    right left [R_key D] i R_value R_key
1420    right left  R_key D    R_value R_key
1421    right left′            R_value R_key
1422
1423 If we adjust our definition of ``W`` to include ``over`` at the end:
1424
1425 ::
1426
1427    W == [fourth] [fourth] while uncons uncons pop over
1428
1429 That will give us:
1430
1431 ::
1432
1433    right left R_key R_value R_key [D] E⁗
1434
1435    right left         R_key R_value R_key [D] cons dipd E⁗′
1436    right left         R_key R_value [R_key D]      dipd E⁗′
1437    right left R_key D R_key R_value                     E⁗′
1438    right left′        R_key R_value                     E⁗′
1439    right left′        R_key R_value                     swap
1440    right left′ R_value R_key
1441
1442 So:
1443
1444 ::
1445
1446    E′ == roll> popop E″
1447
1448    E″ == rest E‴
1449
1450    E‴ == [dup W] dip E⁗
1451
1452    E⁗ == cons dipdd swap
1453
1454 Substituting:
1455
1456 ::
1457
1458    W == [fourth] [fourth] while uncons uncons pop over
1459    E′ == roll> popop rest [dup W] dip cons dipd swap
1460    E == [
1461        [[pop third not] pop fourth]
1462        [[pop fourth not] pop third]
1463        [[E′] cons infra]
1464    ] cond
1465
1466 Minor rearrangement, move ``dup`` into ``W``:
1467
1468 ::
1469
1470    W == dup [fourth] [fourth] while uncons uncons pop over
1471    E′ == roll> popop rest [W] dip cons dipd swap
1472    E == [
1473        [[pop third not] pop fourth]
1474        [[pop fourth not] pop third]
1475        [[E′] cons infra]
1476    ] cond
1477
1478 Refactoring
1479 ~~~~~~~~~~~
1480
1481 ::
1482
1483    W.rightmost == [fourth] [fourth] while
1484    W.unpack == uncons uncons pop
1485    W == dup W.rightmost W.unpack over
1486    E.clear_stuff == roll> popop rest
1487    E.delete == cons dipd
1488    E.0 == E.clear_stuff [W] dip E.delete swap
1489    E == [
1490        [[pop third not] pop fourth]
1491        [[pop fourth not] pop third]
1492        [[E.0] cons infra]
1493    ] cond
1494    T> == [dipd] cons infra
1495    T< == [dipdd] cons infra
1496    R0 == over first swap dup
1497    R1 == cons roll> [T>] [E] [T<] cmp
1498    BTree-Delete == [pop not] swap [R0] [R1] genrec
1499
1500 By the standards of the code I’ve written so far, this is a *huge* Joy
1501 program.
1502
1503 .. code:: python
1504
1505     DefinitionWrapper.add_definitions('''
1506     first_two == uncons uncons pop
1507     fourth == rest rest rest first
1508     ?fourth == [] [fourth] [] ifte
1509     W.rightmost == [?fourth] [fourth] while
1510     E.clear_stuff == roll> popop rest
1511     E.delete == cons dipd
1512     W == dup W.rightmost first_two over
1513     E.0 == E.clear_stuff [W] dip E.delete swap
1514     E == [[[pop third not] pop fourth] [[pop fourth not] pop third] [[E.0] cons infra]] cond
1515     T> == [dipd] cons infra
1516     T< == [dipdd] cons infra
1517     R0 == over first swap dup
1518     R1 == cons roll> [T>] [E] [T<] cmp
1519     Tree-Delete == [pop not] [pop] [R0] [R1] genrec
1520     ''', D)
1521
1522 .. code:: python
1523
1524     J("['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'c' Tree-Delete ")
1525
1526
1527 .. parsed-literal::
1528
1529     ['a' 23 [] ['b' 88 [] []]]
1530
1531
1532 .. code:: python
1533
1534     J("['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'b' Tree-Delete ")
1535
1536
1537 .. parsed-literal::
1538
1539     ['a' 23 [] ['c' 44 [] []]]
1540
1541
1542 .. code:: python
1543
1544     J("['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'a' Tree-Delete ")
1545
1546
1547 .. parsed-literal::
1548
1549     ['b' 88 [] ['c' 44 [] []]]
1550
1551
1552 .. code:: python
1553
1554     J("['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'der' Tree-Delete ")
1555
1556
1557 .. parsed-literal::
1558
1559     ['a' 23 [] ['b' 88 [] ['c' 44 [] []]]]
1560
1561
1562 .. code:: python
1563
1564     J('[] [4 2 3 1 6 7 5 ] [0 swap Tree-add] step')
1565
1566
1567 .. parsed-literal::
1568
1569     [4 0 [2 0 [1 0 [] []] [3 0 [] []]] [6 0 [5 0 [] []] [7 0 [] []]]]
1570
1571
1572 .. code:: python
1573
1574     J("[4 0 [2 0 [1 0 [] []] [3 0 [] []]] [6 0 [5 0 [] []] [7 0 [] []]]] 3 Tree-Delete ")
1575
1576
1577 .. parsed-literal::
1578
1579     [4 0 [2 0 [1 0 [] []] []] [6 0 [5 0 [] []] [7 0 [] []]]]
1580
1581
1582 .. code:: python
1583
1584     J("[4 0 [2 0 [1 0 [] []] [3 0 [] []]] [6 0 [5 0 [] []] [7 0 [] []]]] 4 Tree-Delete ")
1585
1586
1587 .. parsed-literal::
1588
1589     [3 0 [2 0 [1 0 [] []] []] [6 0 [5 0 [] []] [7 0 [] []]]]
1590
1591
1592 Appendix: The source code.
1593 --------------------------
1594
1595 ::
1596
1597    fourth == rest_two rest first
1598    ?fourth == [] [fourth] [] ifte
1599    first_two == uncons uncons pop
1600    ccons == cons cons
1601    cinf == cons infra
1602    rest_two == rest rest
1603
1604    _Tree_T> == [dipd] cinf
1605    _Tree_T< == [dipdd] cinf
1606
1607    _Tree_add_P == over [popop popop first] nullary
1608    _Tree_add_T> == ccons _Tree_T<
1609    _Tree_add_T< == ccons _Tree_T>
1610    _Tree_add_Ee == pop swap roll< rest_two ccons
1611    _Tree_add_R == _Tree_add_P [_Tree_add_T>] [_Tree_add_Ee] [_Tree_add_T<] cmp
1612    _Tree_add_E == [pop] dipd Tree-new
1613
1614    _Tree_iter_order_left == [cons dip] dupdip
1615    _Tree_iter_order_current == [[F] dupdip] dip
1616    _Tree_iter_order_right == [fourth] dip i
1617    _Tree_iter_order_R == _Tree_iter_order_left _Tree_iter_order_current _Tree_iter_order_right
1618
1619    _Tree_get_P == over [pop popop first] nullary
1620    _Tree_get_T> == [fourth] dipd i
1621    _Tree_get_T< == [third] dipd i
1622    _Tree_get_E == popop second
1623    _Tree_get_R == _Tree_get_P [_Tree_get_T>] [_Tree_get_E] [_Tree_get_T<] cmp
1624
1625    _Tree_delete_rightmost == [?fourth] [fourth] while
1626    _Tree_delete_clear_stuff == roll> popop rest
1627    _Tree_delete_del == dip cons dipd swap
1628    _Tree_delete_W == dup _Tree_delete_rightmost first_two over
1629    _Tree_delete_E.0 == _Tree_delete_clear_stuff [_Tree_delete_W] _Tree_delete_del
1630    _Tree_delete_E == [[[pop third not] pop fourth] [[pop fourth not] pop third] [[_Tree_delete_E.0] cinf]] cond
1631    _Tree_delete_R0 == over first swap dup
1632    _Tree_delete_R1 == cons roll> [_Tree_T>] [_Tree_delete_E] [_Tree_T<] cmp
1633
1634    Tree-new == swap [[] []] ccons
1635    Tree-add == [popop not] [_Tree_add_E] [] [_Tree_add_R] genrec
1636    Tree-iter == [not] [pop] roll< [dupdip rest_two] cons [step] genrec
1637    Tree-iter-order == [not] [pop] [dup third] [_Tree_iter_order_R] genrec
1638    Tree-get == [pop not] swap [] [_Tree_get_R] genrec
1639    Tree-delete == [pop not] [pop] [_Tree_delete_R0] [_Tree_delete_R1] genrec