2 Examples (and some documentation) for the Words in the Library
3 ==============================================================
7 from notebook_preamble import J, V
12 This is what I like to call the functions that just rearrange things on
13 the stack. (One thing I want to mention is that during a hypothetical
14 compilation phase these "stack chatter" words effectively disappear,
15 because we can map the logical stack locations to registers that remain
16 static for the duration of the computation. This remains to be done but
17 it's "off the shelf" technology.)
55 ``enstacken`` ``disenstacken`` ``stack`` ``unstack``
56 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
58 (I may have these paired up wrong. I.e. ``disenstacken`` should be
59 ``unstack`` and vice versa.)
63 J('1 2 3 enstacken') # Replace the stack with a quote of itself.
73 J('4 5 6 [3 2 1] disenstacken') # Unpack a list onto the stack.
83 J('1 2 3 stack') # Get the stack on the stack.
93 J('1 2 3 [4 5 6] unstack') # Replace the stack with the list on top.
94 # The items appear reversed but they are not,
95 # 4 is on the top of both the list and the stack.
103 ``pop`` ``popd`` ``popop``
104 ~~~~~~~~~~~~~~~~~~~~~~~~~~
136 ``roll<`` ``rolldown`` ``roll>`` ``rollup``
137 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
139 The "down" and "up" refer to the movement of two of the top three items
140 (displacing the third.)
198 ``unit`` ``quoted`` ``unquoted``
199 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
223 J('1 [2] 3 unquoted')
233 V('1 [dup] 3 unquoted') # Unquoting evaluates. Be aware.
253 ``concat`` ``swoncat`` ``shunt``
254 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
258 J('[1 2 3] [4 5 6] concat')
268 J('[1 2 3] [4 5 6] swoncat')
278 J('[1 2 3] [4 5 6] shunt')
286 ``cons`` ``swons`` ``uncons``
287 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
319 ``first`` ``second`` ``third`` ``rest``
320 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
334 J('[1 2 3 4] second')
367 J('[[1] [2 [3] 4] [5 6]] flatten')
375 ``getitem`` ``at`` ``of`` ``drop`` ``take``
376 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
378 ``at`` and ``getitem`` are the same function. ``of == swap at``
382 J('[10 11 12 13 14] 2 getitem')
412 J('[1 2 3 4] 2 drop')
422 J('[1 2 3 4] 2 take') # reverses the order
430 ``reverse`` could be defines as ``reverse == dup size take``
437 J('[1 2 3 1 4] 1 remove')
450 J('[1 2 3 4] reverse')
474 "Swap stack" swap the list on the top of the stack for the stack, and
475 put the old stack on top of the new one. Think of it as a context
476 switch. Niether of the lists/stacks change their order.
480 J('1 2 3 [4 5 6] swaack')
488 ``choice`` ``select``
489 ~~~~~~~~~~~~~~~~~~~~~
513 J('[23 9 7] 1 select') # select is basically getitem, should retire it?
523 J('[23 9 7] 0 select')
536 J('[1 2 3] [6 5 4] zip')
546 J('[1 2 3] [6 5 4] zip [sum] map')
596 ``/`` ``div`` ``floordiv`` ``truediv``
597 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
659 ``%`` ``mod`` ``modulus`` ``rem`` ``remainder``
660 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
721 ``++`` ``succ`` ``--`` ``pred``
722 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
744 ``<<`` ``lshift`` ``>>`` ``rshift``
745 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
772 J('[1 2 3 5] average')
780 ``range`` ``range_to_zero`` ``down_to_zero``
781 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
818 J('[1 2 3 5] product')
868 If we represent fractions as a quoted pair of integers [q d] this word
869 reduces them to their ... least common factors or whatever.
873 J('[45 30] least_fraction')
883 J('[23 12] least_fraction')
897 Get the Boolean value of the item on the top of the stack.
911 J('[] truthy') # Python semantics.
993 | The usual suspects: - ``<`` ``lt`` - ``<=`` ``le``
994 | - ``=`` ``eq`` - ``>`` ``gt`` - ``>=`` ``ge`` - ``not`` - ``or``
1032 Accepts a quoted symbol on the top of the stack and prints its docs.
1046 Parse the string on the stack to a Joy expression.
1052 J('1 "2 [3] dup" parse')
1063 Evaluate a quoted Joy sequence.
1067 J('[1 2 dup + +] run')
1078 ``app1`` ``app2`` ``app3``
1079 ~~~~~~~~~~~~~~~~~~~~~~~~~~
1088 Given a quoted program on TOS and anything as the second stack item run
1089 the program and replace the two args with the first result of the
1093 -----------------------------------
1094 ... [x ...] [Q] . infra first
1100 J('10 4 [sqr *] app1')
1110 J('10 3 4 [sqr *] app2')
1125 Like app1 with two items.
1128 -----------------------------------
1129 ... [y ...] [Q] . infra first
1130 [x ...] [Q] infra first
1136 J('10 2 3 4 [sqr *] app3')
1147 Given an initial value, a predicate function ``[P]``, and a generator
1148 function ``[G]``, the ``anamorphism`` combinator creates a sequence.
1152 n [P] [G] anamorphism
1153 ---------------------------
1160 range == [0 <=] [1 - dup] anamorphism
1164 J('3 [0 <=] [1 - dup] anamorphism')
1177 J('3 4 1 [+] [*] branch')
1187 J('3 4 0 [+] [*] branch')
1200 ... x [P] [Q] cleave
1202 From the original Joy docs: "The cleave combinator expects two
1203 quotations, and below that an item ``x`` It first executes ``[P]``, with
1204 ``x`` on top, and saves the top result element. Then it executes
1205 ``[Q]``, again with ``x``, and saves the top result. Finally it restores
1206 the stack to what it was below ``x`` and pushes the two results P(X) and
1209 Note that ``P`` and ``Q`` can use items from the stack freely, since the
1210 stack (below ``x``) is restored. ``cleave`` is a kind of *parallel*
1211 primitive, and it would make sense to create a version that uses, e.g.
1212 Python threads or something, to actually run ``P`` and ``Q``
1213 concurrently. The current implementation of ``cleave`` is a definition
1214 in terms of ``app2``:
1218 cleave == [i] app2 [popd] dip
1222 J('10 2 [+] [-] cleave')
1230 ``dip`` ``dipd`` ``dipdd``
1231 ~~~~~~~~~~~~~~~~~~~~~~~~~~
1235 J('1 2 3 4 5 [+] dip')
1245 J('1 2 3 4 5 [+] dipd')
1255 J('1 2 3 4 5 [+] dipdd')
1266 Expects a quoted program ``[Q]`` on the stack and some item under it,
1267 ``dup`` the item and ``dip`` the quoted program under it.
1271 n [Q] dupdip == n Q n
1275 V('23 [++] dupdip *') # N(N + 1)
1289 ``genrec`` ``primrec``
1290 ~~~~~~~~~~~~~~~~~~~~~~
1299 General Recursion Combinator.
1301 [if] [then] [rec1] [rec2] genrec
1302 ---------------------------------------------------------------------
1303 [if] [then] [rec1 [[if] [then] [rec1] [rec2] genrec] rec2] ifte
1305 From "Recursion Theory and Joy" (j05cmp.html) by Manfred von Thun:
1306 "The genrec combinator takes four program parameters in addition to
1307 whatever data parameters it needs. Fourth from the top is an if-part,
1308 followed by a then-part. If the if-part yields true, then the then-part
1309 is executed and the combinator terminates. The other two parameters are
1310 the rec1-part and the rec2-part. If the if-part yields false, the
1311 rec1-part is executed. Following that the four program parameters and
1312 the combinator are again pushed onto the stack bundled up in a quoted
1313 form. Then the rec2-part is executed, where it will find the bundled
1314 form. Typically it will then execute the bundled form, either with i or
1315 with app2, or some other combinator."
1317 The way to design one of these is to fix your base case [then] and the
1318 test [if], and then treat rec1 and rec2 as an else-part "sandwiching"
1319 a quotation of the whole function.
1321 For example, given a (general recursive) function 'F':
1323 F == [I] [T] [R1] [R2] genrec
1325 If the [I] if-part fails you must derive R1 and R2 from:
1329 Just set the stack arguments in front, and figure out what R1 and R2
1330 have to do to apply the quoted [F] in the proper way. In effect, the
1331 genrec combinator turns into an ifte combinator with a quoted copy of
1332 the original definition in the else-part:
1334 F == [I] [T] [R1] [R2] genrec
1335 == [I] [T] [R1 [F] R2] ifte
1337 (Primitive recursive functions are those where R2 == i.
1339 P == [I] [T] [R] primrec
1340 == [I] [T] [R [P] i] ifte
1341 == [I] [T] [R P] ifte
1348 J('3 [1 <=] [] [dup --] [i *] genrec')
1381 [predicate] [then] [else] ifte
1385 J('1 2 [1] [+] [*] ifte')
1395 J('1 2 [0] [+] [*] ifte')
1408 V('1 2 3 [4 5 6] [* +] infra')
1413 . 1 2 3 [4 5 6] [* +] infra
1414 1 . 2 3 [4 5 6] [* +] infra
1415 1 2 . 3 [4 5 6] [* +] infra
1416 1 2 3 . [4 5 6] [* +] infra
1417 1 2 3 [4 5 6] . [* +] infra
1418 1 2 3 [4 5 6] [* +] . infra
1419 6 5 4 . * + [3 2 1] swaack
1420 6 20 . + [3 2 1] swaack
1436 Basic loop combinator.
1439 -----------------------
1443 ------------------------
1450 V('3 dup [1 - dup] loop')
1455 . 3 dup [1 - dup] loop
1456 3 . dup [1 - dup] loop
1457 3 3 . [1 - dup] loop
1458 3 3 [1 - dup] . loop
1459 3 . 1 - dup [1 - dup] loop
1460 3 1 . - dup [1 - dup] loop
1461 2 . dup [1 - dup] loop
1462 2 2 . [1 - dup] loop
1463 2 2 [1 - dup] . loop
1464 2 . 1 - dup [1 - dup] loop
1465 2 1 . - dup [1 - dup] loop
1466 1 . dup [1 - dup] loop
1467 1 1 . [1 - dup] loop
1468 1 1 [1 - dup] . loop
1469 1 . 1 - dup [1 - dup] loop
1470 1 1 . - dup [1 - dup] loop
1471 0 . dup [1 - dup] loop
1472 0 0 . [1 - dup] loop
1473 0 0 [1 - dup] . loop
1482 J('10 [1 2 3] [*] map')
1492 J('10 5 [[*][/][+][-]] pam')
1500 ``nullary`` ``unary`` ``binary`` ``ternary``
1501 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1503 Run a quoted program enforcing
1504 `arity <https://en.wikipedia.org/wiki/Arity>`__.
1508 J('1 2 3 4 5 [+] nullary')
1518 J('1 2 3 4 5 [+] unary')
1528 J('1 2 3 4 5 [+] binary') # + has arity 2 so this is technically pointless...
1538 J('1 2 3 4 5 [+] ternary')
1556 Run a quoted program on each item in a sequence.
1559 -----------------------
1564 ------------------------
1568 ... [a b c] [Q] . step
1569 ----------------------------------------
1570 ... a . Q [b c] [Q] step
1572 The step combinator executes the quotation on each member of the list
1573 on top of the stack.
1579 V('0 [1 2 3] [+] step')
1584 . 0 [1 2 3] [+] step
1585 0 . [1 2 3] [+] step
1586 0 [1 2 3] . [+] step
1587 0 [1 2 3] [+] . step
1588 0 1 [+] . i [2 3] [+] step
1589 0 1 . + [2 3] [+] step
1593 1 2 [+] . i [3] [+] step
1594 1 2 . + [3] [+] step
1608 V('3 2 1 2 [+] times')
1619 3 2 1 . + 1 [+] times
1639 ... [P] [Q] b == ... [P] i [Q] i
1640 ... [P] [Q] b == ... P Q
1666 [predicate] [body] while
1670 J('3 [0 >] [dup --] while')
1690 ... [Q] x = ... [Q] dup i
1691 ... [Q] x = ... [Q] [Q] i
1692 ... [Q] x = ... [Q] Q
1698 V('1 [2] [i 3] x') # Kind of a pointless example.
1718 Implements `**Laws of Form**
1719 *arithmetic* <https://en.wikipedia.org/wiki/Laws_of_Form#The_primary_arithmetic_.28Chapter_4.29>`__
1720 over quote-only datastructures (that is, datastructures that consist
1721 soley of containers, without strings or numbers or anything else.)
1755 J('[[[]][[][]]] void')