The Split in APL
Vector 3:2, page 47
Transcribed from the printed issue; not yet reviewed. Read it in the PDF of the issue, page 47
Historically, APL has always suffered from splits; for example Sharp found it necessary to employ files, traps and packages to make their APL into a saleable product. Similarly IBM introduced the idea of the Auxiliary Processor with TSIO. None of these mattered a great deal; you can always cover for differences in the environment. It is changes in the language itself that should worry us, because there is no way you can cover for these. Even here, however some changes matter much more than others:
- Primitive and user-defined operators extended to all functions. This is simply an implementation of a construct that was latent in all APLs anyway!
- Enclose. A new function . . . . relatively harmless.
- Strands. A syntax change.
- Specification expressions to the left of assignment. Another syntax change.
- Bracket Axis notation “MAT+[1]VEC”. A new construct! This has a defined list of target functions and operators (28 and 4 respectively).
Why worry about syntax changes? In ‘old’ APL you only needed two rules to comprehend a line of code:
- Take operators before functions.
- The right argument of any function is the result of the entire phrase to the right of it.
Note the complete incorrectness of the common myth “APL executes from right to left”!
In APL2, the effort of accommodating strands has caused some drastic changes: you now need to refer to an 8-row table of left and right binding strengths, and 13 pages of special rules for the axis notation! Of course the consequences are mostly not noticeable – things keep on working for the wrong reasons. However you occasionally trip over something like:
'ABCDE'[2] ..... works as expected
2 3 5 7[2] ..... gives a RANK ERROR
(2 3 5)(7[2]) ..... is what the interpreter reads it as!
The Original Structure of APL¶
Before there was any implementation at all, APL had:
| Variables | 3 4 5 or 'ABC' |
| Scalar functions | + - * |
| Operators | / . \ |
| Assignment | Copula |
| Punctuation | () |
This structure had the twin virtues of a simple syntax and a completely uniform extension to arrays. Since that time there have been numerous departures, and the occasional return to simplicity.
| Departures | Return to Simplicity |
|---|---|
| Mixed functions (names for things you don’t really understand) | Function Rank |
| MAT[I;J;K] MAT[I;J;K] assign X |
Pick and Merge operators |
| Axis specification (e.g. rotation) | Rank operator |
| Comments and diamonds | Left and right tacks |
| 'FRED IS ';2 | Format function |
. . . but of course you can never withdraw the old versions, only make them obsolescent and hope they slowly die away.
APL2 and Sharp-APL; Major Differences¶
It is interesting to compare the relative weights of the documentation for the respective APLs: the IBM APL2 language reference is roughly 1.5 inches thick and comprises 658 pages; the Sharp APL dictionary is nearer 0.5 inches and a mere 72 pages. Both contain some 10% extraneous information. The two APLs have approached a superficially similar set of extensions from very different directions:
| APL2 | Sharp APL |
|---|---|
| Enclosed arrays and extensions based upon them | Return to original simple structure . . . – Enclose – function rank |
| Strands and modified syntax | Operators . . . . – rank – dual |
| Bracket Axis notation |
Some examples from Sharp APL are:
- the Enclose function. This is a general scalar encoding function, with an exact inverse in ‘disclose’. The properties of an enclosed object are: it always has rank zero; it never matches the object it was enclosed from; it always matches the original object when disclosed. Note that the second property it not true in APL2 . . . if you enclose a sentence such as “I think, therefore I am” the one-letter words “I” cannot be properly represented!
- Function Rank. A primitive like Domino always has rank-2; it applies to 2-dimensional arrays only. If it is used on higher order arrays, it simply applies to all the 2-D arrays within them. Similarly the rank of ‘open ended’ functions (e.g. transpose) can be restricted to certain subarrays with a ‘Rank’ operator.
- the Dual operator. A deceptively simple creature . . . “F dual G” simply applies G then F then the inverse of G. For example “Floor dual Minus” is the same as “Ceiling”; it really comes into its own with nested structures – “F dual Disclose” will disclose an array, apply F to each element and enclose the results. It effectively makes F into a scalar function.
Some Features of APL2¶
Here the emphasis is on easy ways to deal with enclosed arrays. Strand notation is the major example:
I J K is the same as (encl I),(encl J),(encl K)
. . . but why not use a Link function such as
I link J link K (link encloses then catenates)
Stranding neatly elides one symbol, but look at the fate of mathematics which saw fit to do without the “times” symbol in expressions such as “AB + CD”. The unfortunate consequence of this is that “AB” always means “A x B”, so there are no multi-letter names; that’s why mathematicians have to raid every known alphabet, living or dead, for yet more symbols!!
Bracket Axis is another example of an apparently simple idea which exposes a minefield of hidden rules. The problem is that it requires a specific list of applicable functions and operators, and there are numerous ‘special cases’ which don’t work. For example “,[2 3 5] MAT” – the axes must be contiguous in this case.
Summary¶
Arguments based on simplicity are dangerous! Often they really rest on convenience or familiarity, rather than on structure or power. In particular the power of uniformity requires a great deal of study; it takes time to notice the value of a generalised inner-product as opposed to a simple matrix multiply.
Most of [Axis] is covered naturally by Dual and Rank as applied to the existing definition of Ravel; contrast this with the APL2 documentation of Ravel, which comprises 4 pages of detail on: the depth of the result, selective specification, ravel with axis (including lamination) and the empty cases. One simple paragraph would be quite sufficient if the ‘old’ APL simplicity were still with us.