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, fail_fails=False)[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.disenstacken(stack, expression, dictionary)[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_(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] tailrec
== [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. 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)[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 string with a name followed by a double equal sign then one or more Joy functions, the body. for example:

sqr == dup mul

If you want the definition to persist over restarts, enter it into the definitions.txt resource.

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.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(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.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)