Elegant Programming

#~ 1: = #@q:

Chris Burke
cburke@jsoftware.com

This elegant expression provides an interesting exercise for the newcomer to J. The expression contains a hook, a fork, an adverb, a conjunction, and a constant function. It is fair to say that once you understand this expression, then you also understand the essence of functional programming in J.

First lets use the definition, as follows:

   p=: #~ 1: = #@q:
   
   p 2+i.30
2 3 5 7 11 13 17 19 23 29 31
   
   p 123456+i.50
123457 123479 123491 123493 123499 123503

Thus, p selects the primes in a list of positive integers. How does it work?

The definition of p can be read from left to right as:

    select where 1 equals the number of prime factors.

Lets build up this definition step by step.

q: returns the prime factors of its argument, for example:

   q: 123456
2 2 2 2 2 2 3 643

The verb #@q: returns the count of the number of prime factors. Here, the conjunction @ (atop) creates a new verb that applies q: to its argument, then # to the result of q:.

   p0=: #@q:

   p0 123456
8

We next want to generate a boolean where a 1 indicates a prime, i.e. where the count of the number of prime factors is 1. This is achieved by the following fork:

   p1=: 1: = p0

   p1 2+i.12
1 1 0 1 0 1 0 0 0 1 0 1

The 1: needs some explanation. A fork is a sequence of three verbs, f g h where:

   (f g h) x   <=>   (f x) g (h x)

Note that the three elements of a fork are verbs. In the definition of p, the leftmost verb is 1:, which is a verb that returns the value 1, given any argument. Here, J makes clear the difference between a number and a verb that returns that number - this distinction is blurred in standard mathematical notation.

We now use the boolean to select the primes. The selection verb is #, which takes a boolean left argument:

   1 1 0 1 0 1 # 2 3 4 5 6 7
2 3 5 7

In this case, however, we want to use # with the boolean as a right argument. To do so, we create a new verb with the adverb ~ (pass), that swaps its arguments:

   p2=: #~

   2 3 4 5 6 7 p2 1 1 0 1 0 1 
2 3 5 7

(You can read # as select, and #~ as select where.)

Finally, we define p as the hook p2 p1, giving us the original definition of p. A hook is a sequence of two verbs f g, where:

   (f g) x   <=>   x f g x

Box Display

Box display helps clarify the structure of functional expressions, and should be used by default as a learning aid. You graduate from the school of functional programming when you find that you no longer need box display to read functional expressions! For example:
   p
+-----+---------------+
|+-+-+|+--+-+--------+|
||#|~|||1:|=|+-+-+--+||
|+-+-+||  | ||#|@|q:|||
|     ||  | |+-+-+--+||
|     |+--+-+--------+|
+-----+---------------+

In box display, elements are grouped into twos and threes, as follows:

With this in mind, we can see from the above box display that p is a hook. Its left element is the result of applying the adverb ~ to the verb #. The right element is a fork, whose rightmost element is the result of applying the conjunction @ to the verbs # and q:.

Here are a couple more examples to illustrate:

   t0=: +/ @ (1: = (+. i.))

   t0
+-----+-+--------------+
|+-+-+|@|+--+-+-------+|
||+|/|| ||1:|=|+--+--+||
|+-+-+| ||  | ||+.|i.|||
|     | ||  | |+--+--+||
|     | |+--+-+-------+|
+-----+-+--------------+

Here t0 is the result of applying @, with a left argument of sum ( +/), and a right argument of a fork, whose rightmost element is the hook +. i. .

The expression +. i. computes the GCD (+.) of an integer and all the integers below it. For example,

   (+. i.) 12
12 1 2 3 4 1 6 1 4 3 2 1

Thus, t1 defined below takes an integer argument and computes which integers below it are relatively prime to it (i.e. the GCD is 1):

   t1=: 1: = (+. i.)

   t1 12
0 1 0 0 0 1 0 1 0 0 0 1

Therefore t0, which is defined as +/ @ t1, is Euler's totient function, i.e. the number of integers below a number that are relatively prime to it.

   t0 12
4

A more efficient version is:

   t3=: * -.@%@~.&.q:

   t3 12
4

Can you read its box display?

   t3
+-+-----------------------+
|*|+---------------+--+--+|
| ||+--------+-+--+|&.|q:||
| |||+--+-+-+|@|~.||  |  ||
| ||||-.|@|%|| |  ||  |  ||
| |||+--+-+-+| |  ||  |  ||
| ||+--------+-+--+|  |  ||
| |+---------------+--+--+|
+-+-----------------------+