Do APL2 and J Come up to Scratch?
Vector 14:1, page 46
Transcribed from the printed issue; not yet reviewed. Read it in the PDF of the issue, page 46
There are now two broadly comparable array languages which are widely available to ad hoc problem-solvers.
Chris Burke, on p.119 of part (3) of his series explaining the J way of thinking [1], states that "..in APL it would be unusual to define new operators to solve problems". If this is really the case, I find it regrettable. In the pages immediately preceding his article [2], I demonstrated how operator programming in APL provides elegant means of programming general routines for numeric integration — more elegant in my view than their analogues in J — and further, a substantial part of ‘APL2 in Depth’ [3] (for which modesty forbids me to make an explicit recommendation) is devoted to illustrations of how operator programming in quite ordinary applications can help to exploit APL2 to good advantage.
The present article builds up to a further demonstration of how operator programming in APL matches the use of adverbs in J, and makes explicit comparisons between the two languages in the context of their relative suitability for solving a pragmatic problem of the sort in which they have, historically speaking, excelled other high level languages. The intention is not to extol one over the other, but rather to articulate features arising in ad hoc programming which incline the problem solver towards one or other, or in the case of J, towards one or other of the two programming styles which it supports, namely tacit versus explicit programming.
The problem chosen concerns a motor manufacturer who has decided to commit part of the advertising budget for a new model to the distribution of a scratch cards containing names of drivers occupying various places in a race. The aim is that the average sum per card given away by way of prize money should be £5. Four schemes have been proposed, as follows:
A. Each card has four positions; if the customer reveals the winning driver’s name, he wins £20. B. As for A, except that if he reveals the winning driver he wins £15, and if he reveals the runner-up driver he wins £5. C. Each card has two rows of two positions. The customer reveals one name from each row; if the first row choice is ahead of the second, the customer wins £10. D. Each card has three rows of two sections. If the first row selection is ahead of both of those in the other two, the customer wins £15.
In each case, 14,400 cards are to be printed, and these will in equal proportions of possible cards, there being 4!=24 possibilities for A, B and C, and 6!=720 for D. The programming objective is to simulate the distribution of cards under each scheme, and find which are most/least likely to overrun budget.
The first stage is to simulate customer behaviour, and the second to evaluate means and standard deviations as comparative measures of the results.
To begin with scheme A, the function PLAYA R simulates the scratching of R cards and calculation of the cost in prize money distributed.
As stated above, J offers the choice of writing in either of two styles, tacit, which is strongly associated with function composition, and explicit, in which explicit references are made to the left and right arguments x. and y., thereby broadly mirroring APL. In J, verbs model functions in the mathematical sense of transformations of data, and a train of J verbs models a single function which is a composition of the functions corresponding to its component verbs. The explicit approach in J applied to PLAYA results in an almost literal transliteration of the APL2 function:
which is strongly reminiscent of what was known at one time in APL circles as "direct definition".
It is instructive to write a tacit form of playa:
and then to ask why this has so much less appeal than the explicit form. First the algorithm is bestrewn with constants, 20, 0, 4, and secondly things happen in sequence, as indicated by the two @ conjunctions, that is n random integers between 0 and 3 are generated, THEN each is compared with 0, THEN multiplication by 20 takes place, THEN everything is summed. This leads to the following two general observations:
- Constants militate against tacit programming.
- Actions in sequence militate against tacit programming.
Now consider scheme B, and compare an APL2 version and a J version (header lines in the former will be omitted, because these are identical apart from the function name):
In the APL2 form explicit enclosure arises because two objects, one in APL2 and one in J, which are of identical appearance in display, for example:
may be far from identical in structure. The former is an array of scalars, the latter a stack of two rank 1 objects. This leads to the observation, which was also made in [1]:
- Explicit enclosure in APL2 may correspond to using objects of non-scalar rank in J.
Now compare J and APL2 alternatives for scheme C.
Scheme D in APL is
The function FN suggests strongly the fork construction in J. There is a core function "equals", to which preliminary transformations have to be applied, namely "first" ({.) to form the left side of the comparison, and "take minimum value" (<./) to form the right. The composite verb is {.=<./, which need not be explicitly named — bracketing the characters {.=<./ is sufficent both to define it, and embed it in an explicit or tacit program. This unnamed verb must be applied at rank 1 level to each of the "three-out-of-six" selections without repetition, followed by the usual computation of prize money:
The fork is an instance of more general J function compositions, defined by e.g. atop, with, and under, which leads to the generalisation:
- J function compositions do not need to be explicitly named.
Mean and standard deviation are described as
in APL2, and as
in J, mean is defined in the style of APL in-line assumption, which leads to a further generalisation:
- Function (that is verb) definitions can be made in-line in J, which is not possible in APL2.
The formula
can be repeated in turn for each of the four "play" verbs, which suggests defining an adverb:
The use of the gerund along with the conjunction "oblique" (/.) allows two functions to be composed in the sense that the results of the composition is the join of both applied separately. In APL2 this requires two calls followed by an explicit join. This leads to a further generalisation:
- Gerunds can join verbs at the function level where an explicit join at the result level is required in APL2.
Another way of expressing this is to say that J provides the facility to model function arrays. As an aside, the verb playa msd is an instance of a niladic J verb, since the argument is effectively hidden within the adverb.
The entire experiment is now described as:
In APL2, the analogue of an adverb is an operator:
leading to the matching experiment as:
The display of results has been suppressed, so as not to spoil the excitement in advance for any readers who want to try out the experiment for themselves!
The corresponding generalisation as suggested at the start is:
- Adverbs in J often correspond to operators in APL2.
The simulations described above were run on J for Windows under Windows 95, and on two available APL2 systems, namely APL2 for Windows 95 and APL2/PC. Execution times of course depend on the size of the data, but are consistently in the ratios 3:2:1. Presumably there is a message that if speed is important, avoid the paraphernalia of Windows!
References¶
- APL and J (3): Operators – Reduce, Scan, Outer Product, Chris J. Burke, Vector 13.3 January 1997, pp.118-126
- J and APL Operators – Reduce, Norman Thomson, Vector 13.3 January 1997, pp.112-118
- APL2 in Depth, Norman D. Thomson and Raymond P. Polivka, Springer-Verlag, 1995
Typesetter’s Note¶
In Dyalog APL 7.3 you can get very close indeed to the J syntax with: