Skip to content

J-ottings 39: All Verbs are Monadic

Vector 20:3, page 43

language design programming techniques mathematics and statistics

Transcribed from the printed issue; not yet reviewed. Read it in the PDF of the issue, page 43

Read on – you will find this article is full of interest! And no, its title is not an aberration like signing up to the Flat Earth Society – what I contend is that the concept of valence in J, and indeed in APL, is necessary only at the surface level of language. At interpretation time, one argument of a dyadic verb must be fetched before the other, which means that argument marshalling is necessarily non-symmetric, i.e. 2+3 is not the same as 3+2. In the case of 2+3 an intermediate verb, call it two-add, is created, which is then presented with 3 as argument. This idea arises more generally in computing science, where the idea of argument bonding is known as “currying” after the American logician H. Curry. Indeed the J documentation explicitly offers “curry” as an alternative name for bond (&).

At a surface level J-users do not need to be aware of this, and rightly perceive an inherent symmetry between the left and right arguments of dyadic verbs. However, the inadequacy of this view becomes apparent in applying the power conjunction, as in, for example, 2(+^:4)3. Is two-add to be applied four times to 3 to give 11, or is three-add to be applied four times to 2 to give 14? The answer is the former, illustrating that dyadic verbs are in reality a cover for a two-stage process of “bond left, then apply right”.

Sooner or later every J user becomes frustrated by the fact that verbs must be either monadic or dyadic – how nice it would be to have triadic or even n-adic verb forms to use like argument lists in C++ or Java! But if all verbs are monadic, and thus describable as word groups of the form NV (noun plus verb), then, since the physical placement of the arguments is irrelevant to valence, a dyadic verb can be represented as N(NV) A triadic verb in this notation would be represented as N(N(NV)), and verbs with multiple arguments would have the description NnV. In theory at least, universal monadicity is a liberation which gives J users the power of n-adic verbs!

At this point I return to earth (flat or otherwise) to consider some expressions with superficially triadic verbs. The first evaluates a linear function such as px + y where x and y are lists of equal length, and the calculation is repeated over a range of values of p. To be more specific, think about simple interest calculations and make x = 4 40 (periodic increments), y = 100 1000 (capital sums) and p = 1 2 3 (periods), so that there are three result lists x + y, 2x + y, and 3x + y.

One way to do this which is closely related to the algebraic statement and uses verb rank, is

   (1 2 3*/4 40)+"1(100 1000)     NB. basically p*x + y
104 1040
108 1080
112 1120

However explicit verb rank can be avoided by using the equivalent expression

   1 2 3(+&4 40)100 1000          NB. basically p(+&x)y

This second version is effectively triadic plus, and, interestingly, contains no multiplication symbol. Bonding the verb + with the noun 4 40 creates a superficially dyadic verb +&4 40, call it add-four-forty-to, which becomes bound to 1 2 3 to form a monadic verb, call it repeat3-add-four-forty-to, which is applied to the argument 100 1000. The notion of repeat3-add-four-forty-to may be a little harder to grasp than that of two-add, although in the context of simple interest it can be given a more meaningful name such as repeat3-add-increments-of-interest-to.

The J Dictionary definition of bond (&) shows why this second version works, but first, it is worth commenting on the apparent paradox whereby although + is the only verb, the effect of repeat3-add-four-forty-to is to multiply the list 1 2 3 by 4 and 40 separately and then add the results to 100 and 1000 respectively. What would happen if 4 40 and + were reversed to give a verb which would logically be called four-forty-add-to? The result of 1 2 3(4 40&+)100 1000 is no different from that of 1 2 3(+&4 40)100 1000, but if the argument of the opening paragraph is correct the verbs four-forty-add-to and add-four-forty-to are functionally different. To investigate this question change + to a non-commutative verb:

   (1 2 3 4 5(-&4 40)100 1000);1 2 3 4 5(4 40&-)100 1000
+-------+--------+
|96 960 |_96 _960|
|92 920 |100 1000|
|88 880 |_96 _960|
|84 840 |100 1000|
|80 800 |_96 _960|
+-------+--------+

The first box contains in its columns the results of subtracting 4 40 once, twice, thrice, etc. in succession, which is what might be expected, but what about the second box? It shows that the lists 100 1000 and _96 _960 alternate, that is, either there is a single subtraction of 100 1000 from 4 40 or else nothing at all happens, depending on whether the corresponding left argument item is odd or even. So what is going on?

At this point return to the formal definition of compose as given in the J Help file:

   x m&v y ↔ m&v^:x y

Take m&v to be 4 40&+ so that 1 2 3(4 40&+)100 1000 means (4 40&+)^:1 2 3(100 1000), that is add 4 40 to 100 1000 once, twice and three times, which is equivalent to multiplying 1 2 3 by 4 and 40 respectively and then adding 100 1000. (4 40&-) means that 4 40 is subtracted-from a given number of times; applying the bonded verb a second time means combining four-forty-subtract-from and four-forty-subtract-from before any reference to any other data is made. Now four-forty-subtract-from is an idempotent operation, that is, successive executions cancel each out like a toggle switch, and so the only two final possibilities are to subtract 4 40 once or not at all – precisely what was observed. On the other hand, changing the composed verb to -&4 40 means that the verb -&4 40 is bonded with 1 2 3 so that subtract-four-forty-from is subtracted once, twice, thrice etc. from the right argument, which is always the object to which a complex verb is finally applied.

The logic can be seen even more clearly by comparing the expressions

   5(2 3&%)6 NB. (two-and-three-divide-by 5 times)6
0.333333 0.5 NB.  .. equivalent to (2 3&%)6

   5(%&2 3)6 NB. (divide-by-two-and-three 6) 5 times
0.1875 0.0246914

or, to underline these points:

   2 3% 2 3% 2 3% 2 3% 2 3% 6
0.333333 0.5

   ((((6%2 3)%2 3)%2 3)%2 3)%2 3
0.1875 0.0246914

Now replace + with * to investigate triadic times:

   1 2 3(*&1.04 1.05)100 1000     NB. basically p(*&x)y
    104    1050
 108.16  1102.5
112.486 1157.63

These results are compound interest calculations, and since *, like +, is commutative they are unaffected by replacing (*&1.04 1.05) with (1.04 1.05&*). Now, instead of px + y over a range of values of x and y, the result is yxp, this in spite of there being no explicit exponentiation present.

With division, the results are analogous to those with minus, viz. either just two alternating results arise if the constants are on the left of the bond, or a list y1/1.04p, y2/1.05p if they are on the right. The latter case evaluates net present values as in:

   1 2 3(%&1.04 1.05)100 1000
96.1538 952.381
92.4556 907.029
88.8996 863.838

Do not confuse these problems with the somewhat similar problem of evaluating a linear function, say 2x + 3y, at all points on a grid defined by a list of x values, say 0 10, and a list of y values such as 0 1 2 3 4 5. The grid points are generated by ,"0/ and a dot product generates the function values:

   (+/ .*&2 3)0 10,"0/0 1 2 3 4 5
 0  3  6  9 12 15
20 23 26 29 32 35

When triadic expressions are consolidated into user-defined verbs, the surface constraint of “not more than two arguments” has to be observed, and subsequent arguments must be built in as illustrated in the examples below, which obtain the same compound interest and net present value information obtained earlier:

   ci=.*&100 1000@:(^/)   NB. build in the capital sums
                          NB. call is 1.04 1.05 ci 1 2 3
   npv=:%&1.04 1.05       NB. build in the discount rates NB.
call is 1 2 3 npv 100 1000

To summarise so far, provided that x and y are equal in length p(+&x)y means add x to y p times with feedback to give y+px, and p(*&x)y means multiply x by y p times with feedback to give values of yxp. Similarly p(-&x)y evaluates y–px and p(%&x)y evaluates y/xp. The paradox observed earlier can be explained because, with feedback, multiplication is repeated addition and exponentiation is repeated multiplication.

Now look at a four parameter problem, for example valuing a savings plan where there is a mixture of compound interest at 1.05% and periodic additions of 4 are applied to an initial capital of 100. After the first year the value is.

   1((+&1.05)&4)100  NB. basically p((+&k)&x)y
109

and in principle the values for the next two years are 2 3((+&1.05)&4)100. However, the interpreter requires that powers higher than 1 must be integers (or at least multiples of 0.5), so this expression gives a domain error.

Nevertheless 4-adic plus should not be discounted. Consider

   0 1 2 3 4((3&+)&2)0 1 2 3 4 5 6 7 8 9
 0   1   2   3   4   5   6   7   8   9
 2   5   8  11  14  17  20  23  26  29
 8  17  26  35  44  53  62  71  80  89
26  53  80 107 134 161 188 215 242 269
80 161 242 323 404 485 566 647 728 809

The first row in this table is just i.10 since according to the power definition of bond applying something 0 times means returning the right argument unchanged. Call the first row values n, then the second row is the series 3n+2 (that is using the middle arguments), the third row is the series 3(3n+2)+2, that is 9n+8, the third row is 27n+26 and so on, whereas each column is a series 3n+2 with feedback, using the first row as start values.

If the arguments of 4-adic plus are lists, the scalar rule that repeated application of addition is equivalent to multiplication has to take into account that repeated operations on lists generate lists of lists. Inspection of the following expression shows that it returns the results of applying 2x+4 and 3x+40 twice with feedback to initial values 100 1000

   2((2 3&+)&4 40)100 1000
 412  652
 684 1060

4012 6052
6084 9160

Returning to the savings plan problem which was left in limbo, this can be addressed using the verb base (#.). For example, if an initial capital sum of 100 attracts 5% compound interest and also 4 units are added every period, the values in the first three years are:

   1 2 3(#.&1.05 4)100  NB. basically p #.x y (y scalar)
109 118.45 128.373

Because base is not a scalar verb, a modest amount of adjustment has to made in order to replicate the calculation over several capital sums:

   1 2 3 (#.&1.05 4)"(1)0,.,100 1000
 109 118.45 128.373
1054 1110.7 1170.24

The next question is whether there are primitive verbs other than + and * for which triadic application leads to useful results. One such is triadic shift:

   0 1 2(1&|.)'ABCDEFGHIJK'
ABCDEFGHIJK
BCDEFGHIJKA
CDEFGHIJKAB
   (+/ .*&2 3)1 2 3,"0/6 8
20 26
22 28
24 30

which does progressive 1-shifts, and generalises to n-shifts:

   a=.'ABCDEFGHIJK'
   0 1 2(3&|.)a
ABCDEFGHIJK
DEFGHIJKABC
GHIJKABCDEF

This could also be written 0 3 6 |."0 1 a using explicit rank. Neither of these alternatives is inherently superior to the other. As is often the case, J provides different ways of expressing ideas, and the choice between a bonding or a verb rank approach here is purely a matter of user preference.

Another example is the progressive reduction of a list, n items at a time (triadic drop):

   t=.'parallelogram'
   0 1 2(2&}.)  t
parallelogram
rallelogram
llelogram

which again has an alternative explicit rank formulation 0 2 4 }."0 1 t.

A matching verb for progressively building up a list is triadic append:

   1 2 3 ('ab'&,)''
ab
abab
ababab

which is an alternative to 'ab',^:1 2 3 ''

In summary, the conjunction bond allows extension to surface triadicity, thereby adding meaningfully to the algorithmic repertoire. And because beneath the surface all verbs are actually monadic, extension with further explicit bonds allows 4-adicity and beyond. Thereafter the number of useful applications begins to thin out, and also use with lists can lead to rank explosion if care is not exercised – I wonder if the Flat Earth Society has some interesting n-adic problems waiting in the wings …

Double dyadic verbs

   f=.2 3&+

   f 6
8 9
   5 f 6      NB. (2*5) + 6 , (3*5) + 6
16 21
   f/4 5 6    NB. (2*(4+5))+6 , (3*(4+5))+6
24 33

   g=.2 3&*

   g 6
12 18
   5 g 6      NB. (2^5) * 6 , (3^5) * 6
192 1458
   g/4 5 6    NB. (2^(4+5))*6 , ((3^(4+5))*6
3072 118098

   j=.2 3&$

   $5 j 6         NB. (2,(5$3))$6
2 3 3 3 3 3
   $j/4 5 6   NB. (2,(4+5)$3)$6
2 3 3 3 3 3 3 3 3 3

To calculate 2x + 3y for x = 1 2 3 and y = 6 8, a rank based solution is

   f=.+/@:(2 3&*)
   f"(1)1 2 3,"0/6 8
   (+/@:(2 3&*)"1)1 2 3,"0/6 8   NB. (..p..)x,"0/y
20 26
22 28
24 30

Common Mean

   am=: +/ %   #          NB. arithmetic  mean
   gm=: */ %:~ #            NB. geometric  mean
   cm=: [: {. (am,gm)^:_    NB. common mean
   c=.cm@:(1&,@%@%:)
   c 2
0.847213
ser=.3 :0
t=.(am,gm)^:(i.10)1,%%:y.
'a b'=.|:t
r=.+/\ (2^i.#a) * a -&*: b
)
conv=.(*:@c)%-.@{:@ser
   conv 3
1.5708