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.Def(name, body)[source]

Definitions created by inscribe.

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)[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)[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_(S)[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.disenstacken(stack)[source]

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

joy.library.divmod_(S)[source]

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

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

joy.library.drop(stack)[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(n)[source]

Return the floor of x as an Integral.

This is the largest integer <= x.

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

Compiled GCD function.

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] tailrec
  == [I] [T] [R [P] i] ifte
  == [I] [T] [R P] ifte
joy.library.getitem(stack)[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)[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. Does not affect the rest of the 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, d={'!=': <function ne>, '%': <function mod>, '&': <function and_>, '*': <function mul>, '+': <function add>, '++': <function succ>, '-': <function sub>, '--': <function pred>, '/': <function floordiv>, '//': <function floordiv>, '/floor': <function floordiv>, '<': <function lt>, '<<': <function lshift>, '<=': <function le>, '<>': <function ne>, '=': <function eq>, '>': <function gt>, '>=': <function ge>, '>>': <function rshift>, '^': <function xor>, '_Tree_add_Ee': <function _Tree_add_Ee>, '_Tree_delete_R0': <function _Tree_delete_R0>, '_Tree_delete_clear_stuff': <function _Tree_delete_clear_stuff>, '_Tree_get_E': <function _Tree_get_E>, 'abs': <function abs>, 'add': <function add>, 'and': <function and_>, 'app1': <function app1>, 'app2': <function app2>, 'app3': <function app3>, 'at': <function getitem>, 'b': <function b>, 'bool': <function bool>, 'branch': <function branch>, 'ccons': <function ccons>, 'choice': <function choice>, 'clear': <function clear>, 'cmp': <function cmp_>, 'concat': <function concat_>, 'cond': <function cond>, 'cons': <function cons>, 'dip': <function dip>, 'dipd': <function dipd>, 'dipdd': <function dipdd>, 'disenstacken': <function disenstacken>, 'div': <function floordiv>, 'divmod': <function divmod_>, 'drop': <function drop>, 'dup': <function dup>, 'dupd': <function dupd>, 'dupdd': <function dupdd>, 'dupdip': <function dupdip>, 'eq': <function eq>, 'first': <function first>, 'first_two': <function first_two>, 'floor': <function floor>, 'floordiv': <function floordiv>, 'fourth': <function fourth>, 'gcd2': <function gcd2>, 'ge': <function ge>, 'genrec': <function genrec>, 'getitem': <function getitem>, 'gt': <function gt>, 'help': <function help_>, 'i': <function i>, 'id': <function id_>, 'infra': <function infra>, 'inscribe': <function inscribe_>, 'le': <function le>, 'loop': <function loop>, 'lshift': <function lshift>, 'lt': <function lt>, 'map': <function map_>, 'max': <function max_>, 'min': <function min_>, 'mod': <function mod>, 'modulus': <function mod>, 'mul': <function mul>, 'ne': <function ne>, 'neg': <function neg>, 'not': <function not_>, 'or': <function or_>, 'over': <function over>, 'parse': <function parse>, 'pick': <function getitem>, 'pm': <function pm>, 'pop': <function pop>, 'popd': <function popd>, 'popdd': <function popdd>, 'popop': <function popop>, 'popopd': <function popopd>, 'popopdd': <function popopdd>, 'pow': <function pow>, 'pred': <function pred>, 'primrec': <function primrec>, 'rem': <function mod>, 'remainder': <function mod>, 'remove': <function remove>, 'rest': <function rest>, 'reverse': <function reverse>, 'roll<': <function rolldown>, 'roll>': <function rollup>, 'rolldown': <function rolldown>, 'rollup': <function rollup>, 'round': <function round>, 'rrest': <function rrest>, 'rshift': <function rshift>, 'second': <function second>, 'select': <function select>, 'sharing': <function sharing>, 'shunt': <function shunt>, 'sort': <function sort_>, 'sqrt': <function sqrt>, 'stack': <function stack>, 'step': <function step>, 'stuncons': <function stuncons>, 'stununcons': <function stununcons>, 'sub': <function sub>, 'succ': <function succ>, 'sum': <function sum_>, 'swaack': <function swaack>, 'swap': <function swap>, 'swons': <function swons>, 'take': <function take>, 'third': <function third>, 'times': <function times>, 'truthy': <function bool>, 'tuck': <function tuck>, 'uncons': <function uncons>, 'unique': <function unique>, 'unit': <function unit>, 'unswons': <function unswons>, 'void': <function void>, 'warranty': <function warranty>, 'words': <function words>, 'x': <function x>, 'xor': <function xor>, 'zip': <function zip_>, '•': <function id_>})[source]

A decorator to inscribe functions into the default dictionary.

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

Create a new Joy function definition in the Joy dictionary. A definition is given as a quote with a name followed by a Joy expression. for example:

[sqr dup mul] inscribe

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_(S)[source]

Given a list find the maximum.

joy.library.min_(S)[source]

Given a list find the minimum.

joy.library.parse(stack)[source]

Parse the string on the stack to a Joy expression.

joy.library.pm(stack)[source]

Plus or minus

   a b pm
-------------
   a+b a-b
joy.library.pred(S)[source]

Decrement TOS.

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

From the “Overview of the language JOY”:

> The primrec combinator expects two quoted programs in addition to a data parameter. For an integer data parameter it works like this: If the data parameter is zero, then the first quotation has to produce the value to be returned. If the data parameter is positive then the second has to combine the data parameter with the result of applying the function to its predecessor.:

5  [1]  [*]  primrec

> Then primrec tests whether the top element on the stack (initially the 5) is equal to zero. If it is, it pops it off and executes one of the quotations, the [1] which leaves 1 on the stack as the result. Otherwise it pushes a decremented copy of the top element and recurses. On the way back from the recursion it uses the other quotation, [*], to multiply what is now a factorial on top of the stack by the second element on the stack.:

n [Base] [Recur] primrec

   0 [Base] [Recur] primrec
------------------------------
      Base

     n [Base] [Recur] primrec
------------------------------------------ n > 0
   n (n-1) [Base] [Recur] primrec Recur
joy.library.remove(S)[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(S)[source]

Reverse the list on the top of the stack.

reverse == [] swap shunt
joy.library.select(stack)[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)[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_(S)[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(S)[source]

Increment TOS.

joy.library.sum_(S)[source]

Given a quoted sequence of numbers return the sum.

sum == 0 swap [+] step
joy.library.take(stack)[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(S)[source]

Given a list remove duplicate items.

joy.library.void(stack)[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_(S)[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)