In J, every operator is either monadic (taking one argument) or dyadic (an infix operator taking two arguments). Actually, most operators are both, depending on the context. J is noted for its conciseness, but sometimes wiring functions together points-free (by composing them or using higher order functions or "trains") leads to excess verbosity and reduced clarity.
I have devised a very concise points-free notation for hooking together monadic or dyadic functions that are not higher-order. This requires that each operator used is either monadic or dyadic, not both. I will denote monadic operators by beginning letters of the alphabet (a, b, c, ...) and dyadic operators by ending letters of the alphabet (..., x, y, z).
First we start with an abstract syntax tree representing our points-free function declaration. Suppose that our function takes an argument A (which is not a function). Then for the (fully parenthesized) Lisp expression
(lambda (A) (x (y (a A) (b A)) (c (z (d (f A)) (e A)))))
the abstract syntax tree for the body would look like this:
Since all of the leaf nodes are A, we might as well strip them, and use the convention that any function that is at a "leaf" is actually taking an argument of A. This yields:
a y b x. c. d f z e
Which is probably two or even three times as short as what you'd write in your favorite language! Moreover, it's very simple to decode once you learn the syntax, certainly clearer than a bunch of "atops" and "forks" and whatnot.
Essentially, it is an inorder traversal of the tree. Every operator has a number of periods following it that indicate its "power." Power is the opposite of precedence, and reflects how big a subtree a function wants to grab as its arguments. Something with low precedence has high power and vice versa. x and c each have power 1 in the above expression, indicated by the periods following them, and the others have power 0.
If the most powerful operator is a dyad, this is the root. Everything to its left is its left subchild, and everything to its right is its right subchild. Descend recursively on both sides.
If it is a monad mk preceded by some number of monads m1 m2 ... mk, then m1 is the root, with child m2, which has child m3, ..., which has child mk. Necessarily, m1 is the first element of the expression. Descend recursively on everything to the right of mk.
Now write down an inorder traversal of the parse tree. Following each node in the traversal, write a number of periods equal to the power of that node.
I have devised a very concise points-free notation for hooking together monadic or dyadic functions that are not higher-order. This requires that each operator used is either monadic or dyadic, not both. I will denote monadic operators by beginning letters of the alphabet (a, b, c, ...) and dyadic operators by ending letters of the alphabet (..., x, y, z).
First we start with an abstract syntax tree representing our points-free function declaration. Suppose that our function takes an argument A (which is not a function). Then for the (fully parenthesized) Lisp expression
(lambda (A) (x (y (a A) (b A)) (c (z (d (f A)) (e A)))))
the abstract syntax tree for the body would look like this:
x
/ \
y c
/\ \
a b z
\ \ / \
A A d e
\ \
f A
\
A
Note that the argument of a monadic function is always its right child.Since all of the leaf nodes are A, we might as well strip them, and use the convention that any function that is at a "leaf" is actually taking an argument of A. This yields:
x
/ \
y c
/\ \
a b z
/ \
d e
\
f
which I would represent as the very short expressiona y b x. c. d f z e
Which is probably two or even three times as short as what you'd write in your favorite language! Moreover, it's very simple to decode once you learn the syntax, certainly clearer than a bunch of "atops" and "forks" and whatnot.
Essentially, it is an inorder traversal of the tree. Every operator has a number of periods following it that indicate its "power." Power is the opposite of precedence, and reflects how big a subtree a function wants to grab as its arguments. Something with low precedence has high power and vice versa. x and c each have power 1 in the above expression, indicated by the periods following them, and the others have power 0.
Parsing an expression into a tree
Obtain the power of each operator as the count of the number of periods immediately following that operator. Find the leftmost occurrence of an operator with maximum power, except that if a monad and a dyad are tied for first place, choose the dyad even if it appears later.If the most powerful operator is a dyad, this is the root. Everything to its left is its left subchild, and everything to its right is its right subchild. Descend recursively on both sides.
If it is a monad mk preceded by some number of monads m1 m2 ... mk, then m1 is the root, with child m2, which has child m3, ..., which has child mk. Necessarily, m1 is the first element of the expression. Descend recursively on everything to the right of mk.
Creating an expression from a tree
First, obtain the powers of everything. If a monad is the direct parent of a dyad, and the dyad has power p, the monad has power p+1. Otherwise, the monad has power 0. If x is a dyad with a left subtree whose highest-power element has power p, and with a right subtree whose highest-power element has power q, then the power of x is max(p+1, q).Now write down an inorder traversal of the parse tree. Following each node in the traversal, write a number of periods equal to the power of that node.
Examples
x
/ \
y z
/\ /\
a b c d
a y b x. c z d
w
/ \
x y
/\ /\
a z d e
/ \
b c
a x. b z c w.. d y e
w
/ \
x e
/ \
y z
/\ /\
a b c d
a y b x. c z d w.. e
x
/ \
y d
/ \
z e
/\ \
a b c
a z b y. e c x.. d
v
/ \
w x
/ \ / \
y z h i
/\ /\ \
a b c d e
\
f
\
g
a y b w. c z d v.. h e f g x i
x
/ \
y f
/\ \
a b z
/ \
c d
\
e
a y b x. f. c e z d
x
/ \
y c
/\ \
a b d
\
z
/ \
e f
\
g
a y b x. c d. e g z f
a
\
b
\
x
/ \
y z
/\ / \
c d e f
\
g
a b.. c y d g x. e z f
x
/ \
a \
\ \
b \
\ \
y z
/\ / \
c d e f
\
g
a b. c y d g x. e z f
Properties
A list of functions and periods L defines a tree T whose nodes are the functions of L such that:- The inorder traversal of T consists of L, stripped of periods
- The number of children of a node is the same as the arity of the function at that node
- If A is the parent of B, then either
- A has greater power than B
- A and B are both dyads, A has power equal to that of B, and A appears before B in L
- A is a dyad and B is a monad and A has power equal to that of B
- A and B are both monads.
© Bart Parkis
Last modified:Tue May 19 19:07:52 2009