2 # Examples (and some documentation) for the Words in the Library
6 from notebook_preamble import J, V
10 This is what I like to call the functions that just rearrange things on the stack. (One thing I want to mention is that during a hypothetical compilation phase these "stack chatter" words effectively disappear, because we can map the logical stack locations to registers that remain static for the duration of the computation. This remains to be done but it's "off the shelf" technology.)
40 ### `enstacken` `disenstacken` `stack` `unstack`
41 (I may have these paired up wrong. I.e. `disenstacken` should be `unstack` and vice versa.)
45 J('1 2 3 enstacken') # Replace the stack with a quote of itself.
53 J('4 5 6 [3 2 1] disenstacken') # Unpack a list onto the stack.
61 J('1 2 3 stack') # Get the stack on the stack.
69 J('1 2 3 [4 5 6] unstack') # Replace the stack with the list on top.
70 # The items appear reversed but they are not,
71 # 4 is on the top of both the list and the stack.
77 ### `pop` `popd` `popop`
103 ### `roll<` `rolldown` `roll>` `rollup`
104 The "down" and "up" refer to the movement of two of the top three items (displacing the third.)
150 ### `unit` `quoted` `unquoted`
170 J('1 [2] 3 unquoted')
178 V('1 [dup] 3 unquoted') # Unquoting evaluates. Be aware.
195 ### `concat` `swoncat` `shunt`
199 J('[1 2 3] [4 5 6] concat')
207 J('[1 2 3] [4 5 6] swoncat')
215 J('[1 2 3] [4 5 6] shunt')
221 ### `cons` `swons` `uncons`
247 ### `first` `second` `third` `rest`
259 J('[1 2 3 4] second')
285 J('[[1] [2 [3] 4] [5 6]] flatten')
291 ### `getitem` `at` `of` `drop` `take`
293 `at` and `getitem` are the same function. `of == swap at`
297 J('[10 11 12 13 14] 2 getitem')
321 J('[1 2 3 4] 2 drop')
329 J('[1 2 3 4] 2 take') # reverses the order
335 `reverse` could be defines as `reverse == dup size take`
341 J('[1 2 3 1 4] 1 remove')
351 J('[1 2 3 4] reverse')
368 "Swap stack" swap the list on the top of the stack for the stack, and put the old stack on top of the new one. Think of it as a context switch. Niether of the lists/stacks change their order.
372 J('1 2 3 [4 5 6] swaack')
378 ### `choice` `select`
398 J('[23 9 7] 1 select') # select is basically getitem, should retire it?
406 J('[23 9 7] 0 select')
416 J('[1 2 3] [6 5 4] zip')
424 J('[1 2 3] [6 5 4] zip [sum] map')
462 ### `/` `div` `floordiv` `truediv`
512 ### `%` `mod` `modulus` `rem` `remainder`
560 ### `++` `succ` `--` `pred`
578 ### `<<` `lshift` `>>` `rshift`
600 J('[1 2 3 5] average')
606 ### `range` `range_to_zero` `down_to_zero`
636 J('[1 2 3 5] product')
673 If we represent fractions as a quoted pair of integers [q d] this word reduces them to their ... least common factors or whatever.
677 J('[45 30] least_fraction')
685 J('[23 12] least_fraction')
691 # Logic and Comparison
694 Get the Boolean value of the item on the top of the stack.
706 J('[] truthy') # Python semantics.
806 Accepts a quoted symbol on the top of the stack and prints its docs.
817 Parse the string on the stack to a Joy expression.
823 J('1 "2 [3] dup" parse')
830 Evaluate a quoted Joy sequence.
834 J('[1 2 dup + +] run')
842 ### `app1` `app2` `app3`
849 Given a quoted program on TOS and anything as the second stack item run
850 the program and replace the two args with the first result of the
854 -----------------------------------
855 ... [x ...] [Q] . infra first
861 J('10 4 [sqr *] app1')
869 J('10 3 4 [sqr *] app2')
880 Like app1 with two items.
883 -----------------------------------
884 ... [y ...] [Q] . infra first
885 [x ...] [Q] infra first
891 J('10 2 3 4 [sqr *] app3')
898 Given an initial value, a predicate function `[P]`, and a generator function `[G]`, the `anamorphism` combinator creates a sequence.
900 n [P] [G] anamorphism
901 ---------------------------
906 range == [0 <=] [1 - dup] anamorphism
910 J('3 [0 <=] [1 - dup] anamorphism')
920 J('3 4 1 [+] [*] branch')
928 J('3 4 0 [+] [*] branch')
937 From the original Joy docs: "The cleave combinator expects two quotations, and below that an item `x`
938 It first executes `[P]`, with `x` on top, and saves the top result element.
939 Then it executes `[Q]`, again with `x`, and saves the top result.
940 Finally it restores the stack to what it was below `x` and pushes the two
941 results P(X) and Q(X)."
943 Note that `P` and `Q` can use items from the stack freely, since the stack (below `x`) is restored. `cleave` is a kind of *parallel* primitive, and it would make sense to create a version that uses, e.g. Python threads or something, to actually run `P` and `Q` concurrently. The current implementation of `cleave` is a definition in terms of `app2`:
945 cleave == [i] app2 [popd] dip
949 J('10 2 [+] [-] cleave')
955 ### `dip` `dipd` `dipdd`
959 J('1 2 3 4 5 [+] dip')
967 J('1 2 3 4 5 [+] dipd')
975 J('1 2 3 4 5 [+] dipdd')
982 Expects a quoted program `[Q]` on the stack and some item under it, `dup` the item and `dip` the quoted program under it.
984 n [Q] dupdip == n Q n
988 V('23 [++] dupdip *') # N(N + 1)
1000 ### `genrec` `primrec`
1007 General Recursion Combinator.
1009 [if] [then] [rec1] [rec2] genrec
1010 ---------------------------------------------------------------------
1011 [if] [then] [rec1 [[if] [then] [rec1] [rec2] genrec] rec2] ifte
1013 From "Recursion Theory and Joy" (j05cmp.html) by Manfred von Thun:
1014 "The genrec combinator takes four program parameters in addition to
1015 whatever data parameters it needs. Fourth from the top is an if-part,
1016 followed by a then-part. If the if-part yields true, then the then-part
1017 is executed and the combinator terminates. The other two parameters are
1018 the rec1-part and the rec2-part. If the if-part yields false, the
1019 rec1-part is executed. Following that the four program parameters and
1020 the combinator are again pushed onto the stack bundled up in a quoted
1021 form. Then the rec2-part is executed, where it will find the bundled
1022 form. Typically it will then execute the bundled form, either with i or
1023 with app2, or some other combinator."
1025 The way to design one of these is to fix your base case [then] and the
1026 test [if], and then treat rec1 and rec2 as an else-part "sandwiching"
1027 a quotation of the whole function.
1029 For example, given a (general recursive) function 'F':
1031 F == [I] [T] [R1] [R2] genrec
1033 If the [I] if-part fails you must derive R1 and R2 from:
1037 Just set the stack arguments in front, and figure out what R1 and R2
1038 have to do to apply the quoted [F] in the proper way. In effect, the
1039 genrec combinator turns into an ifte combinator with a quoted copy of
1040 the original definition in the else-part:
1042 F == [I] [T] [R1] [R2] genrec
1043 == [I] [T] [R1 [F] R2] ifte
1045 (Primitive recursive functions are those where R2 == i.
1047 P == [I] [T] [R] primrec
1048 == [I] [T] [R [P] i] ifte
1049 == [I] [T] [R P] ifte
1056 J('3 [1 <=] [] [dup --] [i *] genrec')
1080 [predicate] [then] [else] ifte
1084 J('1 2 [1] [+] [*] ifte')
1092 J('1 2 [0] [+] [*] ifte')
1102 V('1 2 3 [4 5 6] [* +] infra')
1105 . 1 2 3 [4 5 6] [* +] infra
1106 1 . 2 3 [4 5 6] [* +] infra
1107 1 2 . 3 [4 5 6] [* +] infra
1108 1 2 3 . [4 5 6] [* +] infra
1109 1 2 3 [4 5 6] . [* +] infra
1110 1 2 3 [4 5 6] [* +] . infra
1111 6 5 4 . * + [3 2 1] swaack
1112 6 20 . + [3 2 1] swaack
1125 Basic loop combinator.
1128 -----------------------
1132 ------------------------
1139 V('3 dup [1 - dup] loop')
1142 . 3 dup [1 - dup] loop
1143 3 . dup [1 - dup] loop
1144 3 3 . [1 - dup] loop
1145 3 3 [1 - dup] . loop
1146 3 . 1 - dup [1 - dup] loop
1147 3 1 . - dup [1 - dup] loop
1148 2 . dup [1 - dup] loop
1149 2 2 . [1 - dup] loop
1150 2 2 [1 - dup] . loop
1151 2 . 1 - dup [1 - dup] loop
1152 2 1 . - dup [1 - dup] loop
1153 1 . dup [1 - dup] loop
1154 1 1 . [1 - dup] loop
1155 1 1 [1 - dup] . loop
1156 1 . 1 - dup [1 - dup] loop
1157 1 1 . - dup [1 - dup] loop
1158 0 . dup [1 - dup] loop
1159 0 0 . [1 - dup] loop
1160 0 0 [1 - dup] . loop
1168 J('10 [1 2 3] [*] map')
1176 J('10 5 [[*][/][+][-]] pam')
1182 ### `nullary` `unary` `binary` `ternary`
1183 Run a quoted program enforcing [arity](https://en.wikipedia.org/wiki/Arity).
1187 J('1 2 3 4 5 [+] nullary')
1195 J('1 2 3 4 5 [+] unary')
1203 J('1 2 3 4 5 [+] binary') # + has arity 2 so this is technically pointless...
1211 J('1 2 3 4 5 [+] ternary')
1224 Run a quoted program on each item in a sequence.
1227 -----------------------
1232 ------------------------
1236 ... [a b c] [Q] . step
1237 ----------------------------------------
1238 ... a . Q [b c] [Q] step
1240 The step combinator executes the quotation on each member of the list
1241 on top of the stack.
1247 V('0 [1 2 3] [+] step')
1250 . 0 [1 2 3] [+] step
1251 0 . [1 2 3] [+] step
1252 0 [1 2 3] . [+] step
1253 0 [1 2 3] [+] . step
1254 0 1 [+] . i [2 3] [+] step
1255 0 1 . + [2 3] [+] step
1259 1 2 [+] . i [3] [+] step
1260 1 2 . + [3] [+] step
1273 V('3 2 1 2 [+] times')
1282 3 2 1 . + 1 [+] times
1299 ... [P] [Q] b == ... [P] i [Q] i
1300 ... [P] [Q] b == ... P Q
1320 [predicate] [body] while
1324 J('3 [0 >] [dup --] while')
1339 ... [Q] x = ... [Q] dup i
1340 ... [Q] x = ... [Q] [Q] i
1341 ... [Q] x = ... [Q] Q
1347 V('1 [2] [i 3] x') # Kind of a pointless example.
1363 Implements [**Laws of Form** *arithmetic*](https://en.wikipedia.org/wiki/Laws_of_Form#The_primary_arithmetic_.28Chapter_4.29) over quote-only datastructures (that is, datastructures that consist soley of containers, without strings or numbers or anything else.)
1391 J('[[[]][[][]]] void')