Function Reference

joy.library

This module contains the Joy function infrastructure and a library of functions. Its main export is a Python function initialize() that returns a dictionary of Joy functions suitable for use with the joy() function.

joy.library.BinaryBuiltinWrapper(f)[source]

Wrap functions that take two arguments and return a single result.

class joy.library.DefinitionWrapper(name, body_text, doc=None)[source]

Provide implementation of defined functions, and some helper methods.

classmethod add_def(definition, dictionary)[source]

Add the definition to the dictionary.

classmethod add_definitions(defs, dictionary)[source]

Scan multi-line string defs for definitions and add them to the dictionary.

classmethod parse_definition(defi)[source]

Given some text describing a Joy function definition parse it and return a DefinitionWrapper.

joy.library.FunctionWrapper(f)[source]

Set name attribute.

joy.library.SimpleFunctionWrapper(f)[source]

Wrap functions that take and return just a stack.

joy.library.UnaryBuiltinWrapper(f)[source]

Wrap functions that take one argument and return a single result.

joy.library.add_aliases(D, A)[source]

Given a dict and a iterable of (name, [alias, …]) pairs, create additional entries in the dict mapping each alias to the named function if it’s in the dict. Aliases for functions not in the dict are ignored.

joy.library.app1(S, expression, dictionary)[source]

Given a quoted program on TOS and anything as the second stack item run the program and replace the two args with the first result of the program.

         ... x [Q] . app1
-----------------------------------
   ... [x ...] [Q] . infra first
joy.library.app2(S, expression, dictionary)[source]

Like app1 with two items.

       ... y x [Q] . app2
-----------------------------------
   ... [y ...] [Q] . infra first
       [x ...] [Q]   infra first
joy.library.app3(S, expression, dictionary)[source]

Like app1 with three items.

       ... z y x [Q] . app3
-----------------------------------
   ... [z ...] [Q] . infra first
       [y ...] [Q]   infra first
       [x ...] [Q]   infra first
joy.library.b(stack, expression, dictionary)[source]
b == [i] dip i

... [P] [Q] b == ... [P] i [Q] i
... [P] [Q] b == ... P Q
joy.library.branch(stack, expression, dictionary)[source]

Use a Boolean value to select one of two quoted programs to run.

branch == roll< choice i
   False [F] [T] branch
--------------------------
          F

   True [F] [T] branch
-------------------------
             T
joy.library.choice(stack, expression, dictionary)[source]

Use a Boolean value to select one of two items.

   A B False choice
----------------------
          A


   A B True choice
---------------------
          B

Currently Python semantics are used to evaluate the “truthiness” of the Boolean value (so empty string, zero, etc. are counted as false, etc.)

joy.library.clear(stack, expression, dictionary)[source]

Clear everything from the stack.

clear == stack [pop stack] loop

   ... clear
---------------
joy.library.cmp_(stack, expression, dictionary)[source]

cmp takes two values and three quoted programs on the stack and runs one of the three depending on the results of comparing the two values:

   a b [G] [E] [L] cmp
------------------------- a > b
        G

   a b [G] [E] [L] cmp
------------------------- a = b
            E

   a b [G] [E] [L] cmp
------------------------- a < b
                L
joy.library.concat_(stack, expression, dictionary)[source]

Concatinate the two lists on the top of the stack.

   [a b c] [d e f] concat
----------------------------
       [a b c d e f]
joy.library.cond(stack, expression, dictionary)[source]

This combinator works like a case statement. It expects a single quote on the stack that must contain zero or more condition quotes and a default quote. Each condition clause should contain a quoted predicate followed by the function expression to run if that predicate returns true. If no predicates return true the default function runs.

It works by rewriting into a chain of nested ifte expressions, e.g.:

      [[[B0] T0] [[B1] T1] [D]] cond
-----------------------------------------
   [B0] [T0] [[B1] [T1] [D] ifte] ifte
joy.library.dip(stack, expression, dictionary)[source]

The dip combinator expects a quoted program on the stack and below it some item, it hoists the item into the expression and runs the program on the rest of the stack.

   ... x [Q] dip
-------------------
     ... Q x
joy.library.dipd(S, expression, dictionary)[source]

Like dip but expects two items.

   ... y x [Q] dip
---------------------
     ... Q y x
joy.library.dipdd(S, expression, dictionary)[source]

Like dip but expects three items.

   ... z y x [Q] dip
-----------------------
     ... Q z y x
joy.library.divmod_(stack, expression, dictionary)[source]

divmod(x, y) -> (quotient, remainder)

Return the tuple (x//y, x%y). Invariant: div*y + mod == x.

joy.library.drop(stack, expression, dictionary)[source]
drop == [rest] times

Expects an integer and a quote on the stack and returns the quote with n items removed off the top.

   [a b c d] 2 drop
----------------------
       [c d]
joy.library.dupdip(stack, expression, dictionary)[source]
[F] dupdip == dup [F] dip

... a [F] dupdip
... a dup [F] dip
... a a   [F] dip
... a F a
joy.library.floor(x)[source]

Return the floor of x as a float. This is the largest integral value <= x.

joy.library.genrec(stack, expression, dictionary)[source]

General Recursion Combinator.

                      [if] [then] [rec1] [rec2] genrec
---------------------------------------------------------------------
   [if] [then] [rec1 [[if] [then] [rec1] [rec2] genrec] rec2] ifte

From “Recursion Theory and Joy” (j05cmp.html) by Manfred von Thun: “The genrec combinator takes four program parameters in addition to whatever data parameters it needs. Fourth from the top is an if-part, followed by a then-part. If the if-part yields true, then the then-part is executed and the combinator terminates. The other two parameters are the rec1-part and the rec2-part. If the if-part yields false, the rec1-part is executed. Following that the four program parameters and the combinator are again pushed onto the stack bundled up in a quoted form. Then the rec2-part is executed, where it will find the bundled form. Typically it will then execute the bundled form, either with i or with app2, or some other combinator.”

The way to design one of these is to fix your base case [then] and the test [if], and then treat rec1 and rec2 as an else-part “sandwiching” a quotation of the whole function.

For example, given a (general recursive) function ‘F’:

F == [I] [T] [R1] [R2] genrec

If the [I] if-part fails you must derive R1 and R2 from:

... R1 [F] R2

Just set the stack arguments in front, and figure out what R1 and R2 have to do to apply the quoted [F] in the proper way. In effect, the genrec combinator turns into an ifte combinator with a quoted copy of the original definition in the else-part:

F == [I] [T] [R1]   [R2] genrec
  == [I] [T] [R1 [F] R2] ifte

Primitive recursive functions are those where R2 == i.

P == [I] [T] [R] primrec
  == [I] [T] [R [P] i] ifte
  == [I] [T] [R P] ifte
joy.library.getitem(stack, expression, dictionary)[source]
getitem == drop first

Expects an integer and a quote on the stack and returns the item at the nth position in the quote counting from 0.

   [a b c d] 0 getitem
-------------------------
            a
joy.library.help_(S, expression, dictionary)[source]

Accepts a quoted symbol on the top of the stack and prints its docs.

joy.library.i(stack, expression, dictionary)[source]

The i combinator expects a quoted program on the stack and unpacks it onto the pending expression for evaluation.

   [Q] i
-----------
    Q
joy.library.id_(stack, expression, dictionary)[source]

The identity function.

joy.library.infra(stack, expression, dictionary)[source]

Accept a quoted program and a list on the stack and run the program with the list as its stack.

   ... [a b c] [Q] . infra
-----------------------------
   c b a . Q [...] swaack
joy.library.initialize()[source]

Return a dictionary of Joy functions for use with joy().

joy.library.inscribe(function)[source]

A decorator to inscribe functions into the default dictionary.

joy.library.loop(stack, expression, dictionary)[source]

Basic loop combinator.

   ... True [Q] loop
-----------------------
      ... Q [Q] loop

   ... False [Q] loop
------------------------
          ...
joy.library.map_(S, expression, dictionary)[source]

Run the quoted program on TOS on the items in the list under it, push a new list with the results (in place of the program and original list.

joy.library.max_(stack, expression, dictionary)[source]

Given a list find the maximum.

joy.library.min_(stack, expression, dictionary)[source]

Given a list find the minimum.

joy.library.parse(stack, expression, dictionary)[source]

Parse the string on the stack to a Joy expression.

joy.library.pm(stack, expression, dictionary)[source]

Plus or minus

   a b pm
-------------
   a+b a-b
joy.library.pred(stack, expression, dictionary)[source]

Decrement TOS.

joy.library.remove(stack, expression, dictionary)[source]

Expects an item on the stack and a quote under it and removes that item from the the quote. The item is only removed once.

   [1 2 3 1] 1 remove
------------------------
        [2 3 1]
joy.library.reverse(stack, expression, dictionary)[source]

Reverse the list on the top of the stack.

reverse == [] swap shunt
joy.library.select(stack, expression, dictionary)[source]

Use a Boolean value to select one of two items from a sequence.

   [A B] False select
------------------------
           A


   [A B] True select
-----------------------
          B

The sequence can contain more than two items but not fewer. Currently Python semantics are used to evaluate the “truthiness” of the Boolean value (so empty string, zero, etc. are counted as false, etc.)

joy.library.sharing(stack, expression, dictionary)[source]

Print redistribution information.

joy.library.shunt(stack, expression, dictionary)[source]

Like concat but reverses the top list into the second.

shunt == [swons] step == reverse swap concat

   [a b c] [d e f] shunt
---------------------------
     [f e d a b c] 
joy.library.sort_(stack, expression, dictionary)[source]

Given a list return it sorted.

joy.library.sqrt(a)[source]

Return the square root of the number a. Negative numbers return complex roots.

joy.library.step(S, expression, dictionary)[source]

Run a quoted program on each item in a sequence.

      ... [] [Q] . step
   -----------------------
             ... .


     ... [a] [Q] . step
  ------------------------
           ... a . Q


   ... [a b c] [Q] . step
----------------------------------------
             ... a . Q [b c] [Q] step

The step combinator executes the quotation on each member of the list on top of the stack.

joy.library.succ(stack, expression, dictionary)[source]

Increment TOS.

joy.library.sum_(stack, expression, dictionary)[source]

Given a quoted sequence of numbers return the sum.

sum == 0 swap [+] step

joy.library.take(stack, expression, dictionary)[source]

Expects an integer and a quote on the stack and returns the quote with just the top n items in reverse order (because that’s easier and you can use reverse if needed.)

   [a b c d] 2 take
----------------------
       [b a]
joy.library.times(stack, expression, dictionary)[source]

times == [– dip] cons [swap] infra [0 >] swap while pop

   ... n [Q] . times
---------------------  w/ n <= 0
         ... .


   ... 1 [Q] . times
---------------------------------
         ... . Q


   ... n [Q] . times
---------------------------------  w/ n > 1
         ... . Q (n - 1) [Q] times
joy.library.unique(stack, expression, dictionary)[source]

Given a list remove duplicate items.

joy.library.unstack(stack, expression, dictionary)[source]

The unstack operator expects a list on top of the stack and makes that the stack discarding the rest of the stack.

joy.library.void(stack, expression, dictionary)[source]

True if the form on TOS is void otherwise False.

joy.library.warranty(stack, expression, dictionary)[source]

Print warranty information.

joy.library.words(stack, expression, dictionary)[source]

Print all the words in alphabetical order.

joy.library.x(stack, expression, dictionary)[source]
x == dup i

... [Q] x = ... [Q] dup i
... [Q] x = ... [Q] [Q] i
... [Q] x = ... [Q]  Q
joy.library.zip_(stack, expression, dictionary)[source]

Replace the two lists on the top of the stack with a list of the pairs from each list. The smallest list sets the length of the result list.

Auto-generated Functions

joy.utils.generated_library.ccons(stack)[source]
(a2 a1 [...1] -- [a2 a1 ...1])
joy.utils.generated_library.cons(stack)[source]
(a1 [...0] -- [a1 ...0])
joy.utils.generated_library.dup(stack)[source]
(a1 -- a1 a1)
joy.utils.generated_library.dupd(stack)[source]
(a2 a1 -- a2 a2 a1)
joy.utils.generated_library.dupdd(stack)[source]
(a3 a2 a1 -- a3 a3 a2 a1)
joy.utils.generated_library.first(stack)[source]
([a1 ...1] -- a1)
joy.utils.generated_library.first_two(stack)[source]
([a1 a2 ...1] -- a1 a2)
joy.utils.generated_library.fourth(stack)[source]
([a1 a2 a3 a4 ...1] -- a4)
joy.utils.generated_library.over(stack)[source]
(a2 a1 -- a2 a1 a2)
joy.utils.generated_library.pop(stack)[source]
(a1 --)
joy.utils.generated_library.popd(stack)[source]
(a2 a1 -- a1)
joy.utils.generated_library.popdd(stack)[source]
(a3 a2 a1 -- a2 a1)
joy.utils.generated_library.popop(stack)[source]
(a2 a1 --)
joy.utils.generated_library.popopd(stack)[source]
(a3 a2 a1 -- a1)
joy.utils.generated_library.popopdd(stack)[source]
(a4 a3 a2 a1 -- a2 a1)
joy.utils.generated_library.rest(stack)[source]
([a1 ...0] -- [...0])
joy.utils.generated_library.rolldown(stack)[source]
(a1 a2 a3 -- a2 a3 a1)
joy.utils.generated_library.rollup(stack)[source]
(a1 a2 a3 -- a3 a1 a2)
joy.utils.generated_library.rrest(stack)[source]
([a1 a2 ...1] -- [...1])
joy.utils.generated_library.second(stack)[source]
([a1 a2 ...1] -- a2)
joy.utils.generated_library.stack(stack)[source]
(... -- ... [...])
joy.utils.generated_library.stuncons(stack)[source]
(... a1 -- ... a1 a1 [...])
joy.utils.generated_library.stununcons(stack)[source]
(... a2 a1 -- ... a2 a1 a1 a2 [...])
joy.utils.generated_library.swaack(stack)[source]
([...1] -- [...0])
joy.utils.generated_library.swap(stack)[source]
(a1 a2 -- a2 a1)
joy.utils.generated_library.swons(stack)[source]
([...1] a1 -- [a1 ...1])
joy.utils.generated_library.third(stack)[source]
([a1 a2 a3 ...1] -- a3)
joy.utils.generated_library.tuck(stack)[source]
(a2 a1 -- a1 a2 a1)
joy.utils.generated_library.uncons(stack)[source]
([a1 ...0] -- a1 [...0])
joy.utils.generated_library.unit(stack)[source]
(a1 -- [a1 ])
joy.utils.generated_library.unswons(stack)[source]
([a1 ...1] -- [...1] a1)