Fifty Shades of J/Chapter 6
Table of Contents ... Glossary ... Previous Chapter ... Next Chapter
- |. (shift) /: (grade up) [ (left) ] (right) ” (rank conjunction) , (append) ; (link) ,. (stitch) [: (cap) rank inheritance, statement separator, mood, transitivity, commutativity, trains, binding
In Functional calculation 3: Structural Ingredients (Vector Vol. 24 nos. 2&3 pp 114-121), Neville Holmes gives useful tables which categorise the structural primitive verbs of J according to their function – ‘what they do’ as opposed to the ‘how they do it’. Accurate use of such verbs requires strict adherence to rules regarding two intimately related quantities, namely punctuation and rank, which leads to a further categorisation of a different kind given in the Appendix of Essay #5: Conjugacy and Rank. What follows in this article is the rationale underlying this classification.
Lynne Truss created a best-selling book on the art of punctuation, famously drawing its title from the story of the panda which, after visiting a restaurant "eats shoots and leaves", a plausible option allowing for a touch of anthropomorphism, and one which might not cause too great a disturbance to other diners.
If on the other hand the panda "eats, shoots and leaves" the effect is likely to be very different.
Much has been made of the manner in which the constructs of J were inspired by and derived from the parts of speech of ordinary language grammar, nouns, verbs and so on, despite which little reference is made to punctuation. While analogies should not be pushed too far – e.g. unlike ‘shoots’, there can never be any verb/noun ambiguity for primitive J objects – the explicit consideration of punctuation by parentheses and space, as well as implicitly through hook and fork, can be helpful in writing and understanding expressions. Compare
((i.#)t);(i.@#)t=.'abcde' ┌─┬─────────┐ │5│0 1 2 3 4│ └─┴─────────┘
can be tempting to think of conjunctions such as @ (atop) as punctuators.
However the role of @ in the above is that of a neologiser, that is, it constructs a new compound verb, call it ‘index-tally’ (or perhaps even ‘indally’), operating in scalar fashion on the items of the object to its right. The operational details of such verbs leads naturally to consideration of one of the most subtle of all J concepts, namely rank.
Consider three compound verbs which differ only in punctuation, that is the placing of the parentheses
v1=:>:@i.@# v2=:>:@(i.@#) v3=:(>:@i.)@#
The effect of all three verbs is the same, that is they are semantically equivalent as demonstrated by
(v1 t);(v2 t);(v3 t=.'abcde') ┌─────────┬─────────┬─────────┐ │1 2 3 4 5│1 2 3 4 5│1 2 3 4 5│ └─────────┴─────────┴─────────┘
This raises general questions such as
- for given verbs a b c , to which, if either, of the two forms a@(b@c) and (a@b)@c is a@b@c necessarily equivalent?
- is a@(b@c) equivalent to (a@b)@c (in mathematical terms: is the conjunction @ associative)?
Intuitively it should not be, for the same sort of reason that "eats, shoots and leaves" has a different meaning from "eats shoots and leaves". The scope rule for conjunctions is that they bind closely on the right, which means that it is (a@b)@c which is equivalent to a@b@c – which of course is guaranteed by the J interpreter. Using conjunctions is analogous to coining new verb-names in English, so that the meaning of v2 is ‘increment-(index-tally)’ as opposed to v3 which is ‘(increment-index)-tally’ (‘incrindally’ as opposed to ‘increxally’!).
In learning J it takes a degree of mental adaptation to grasp the idea of a compound verb such as ‘index-tally’ let alone triple compounds like v2 and v3, and also to appreciate that the meaning of ‘index-tally’ is not “index then tally”. This difference is demonstrated by
(|.@*:)t=.1 2 2 3 NB. rotate-square 1 4 4 9 (|.@:*:)t NB. rotate-following-square 9 4 4 1
which suggests that the J terminologies “a atop b” and “a at b” are rendered more comprehensibly in pseudo-English as ‘a-b’ and ‘a-following-b’. The compound verb ‘rotate-square’ (‘roquare’?) has rank zero because it takes on the rank of its rightmost component, a property which for obvious reasons is called rank inheritance (see Essay #2: A Composition on Composition). However, in ‘rotate-following-square’ the colon in @: can be thought of as signalling a pause in which rank is readjusted before the left hand verb is executed.
The nature of the arguments which can be presented to a conjunctionally compounded verb depend on the arguments presented to its rightmost verb, and so returning to v1, v2 and v3, all of these require an argument acceptable to tally. This can be any J object since all J objects are fundamentally lists and so can be tallied at their topmost level. Also since the three verbs are to be executed in right to left succession it would seem, superficially at least, to make no difference how they are parenthesised as the transformed data is ‘passed down the line’ from right to left. However, as ‘rotate-square’ shows, rank inheritance has to be taken into account in the general case.
Verbs can be categorised according to their rank properties in a manner comparable to conjugation in classical language grammar (see Appendix to Essay #5: Conjugacy and Rank). Every verb has a rank list, viz.
monadic rank left rank right rank
which can always be explicitly obtained by applying the basic characteristics adverb b. and using 0 as right argument of the resulting verb. Rank can be infinite, and most verbs of infinite rank are structural, meaning that, like box, they are designed to operate on their argument or arguments as a whole, that is, they do not ‘penetrate’ the outer shells of objects.
Grade-up (/:) is a useful illustration of the notion of infinite rank because however large the rank of its argument, it orders objects at the next lowest rank level, thus
/:i.2 10 20 30 40 NB. grade up two 4 dimnl objects 0 1 /:i.5 10 20 30 40 NB. grade up five 4 dimnl objects 0 1 2 3 4
Infinite (_) is the default verb rank, which is also the rank of all but the simplest user-defined verbs, since the interpreter could potentially be forced to perform exhaustive and unproductive effort to work out the de facto rank, and so it makes the ‘safe’ assumption of infinite. However this can be over-ridden by explicit use of the rank conjunction as in
mean=:+/ % # mean0=:(+/%#)"0 NB. scalarised mean (mean i.5);(mean0 i.5) ┌─┬─────────┐ │2│0 1 2 3 4│ └─┴─────────┘ (mean b.0);(mean0 b.0) ┌─────┬─────┐ │_ _ _│0 0 0│ └─────┴─────┘
Returning to ‘rotate-square’ whose rank list is 0 0 0, although rotate is a rank 1 verb, rank inheritance forces rotation at rank 0 (that is, equivalent to an explicit "0) and so it inherits a list of rank 0 objects (scalars) each of which has to be treated as a list, with the result that is does nothing. However, if rank is not inherited as with |.@:*: , then rotation applies to the list of squares as a single entity of rank 1.
The equivalence of a@(b@c) and (a@b)@c (i.e. associativity) depends on the rank of the inheriting verb being no greater than that of the giving verb, something which will certainly take place if a, b and c are all rank 0 verbs, but which has to be examined in terms of verb rank properties when this is not the case. Rank inheritance from higher to equal or lower creates no problems as in
(>:@i.)6 NB. rank 0 inherits rank 1 1 2 3 4 5 6
(/:@>:)7 3 5 NB. rank infinite inherits rank 0 0 0 0
in which each of the three incremented values is upgraded separately, with
(>:@/:)7 3 5 NB. rank 0 inherits rank infinite 2 3 1 (/:@|:)i.2 3 NB. both ranks infinite .. 0 1 2 (|:@/:)i.2 3 NB. .. but the result is different 0 1
The next two examples involve verbs of equal ranks, again there is no inheritance issue, although changing the order of the verbs gives a different result because the grade-up of a transposed matrix is not the same as the transpose of a grade-up of the original matrix.
(/:@|:)i.2 3 NB. both ranks infinite .. 0 1 2 (|:@/:)i.2 3 NB. .. but the result is different 0 1
Mood, Transitivity and Commutativity
J verbs are restricted to the imperative mood apart from the verb ‘to be’ (copula). Mood is independent of transitivity, meaning that a verb is either monadic (intransitive) or dyadic (transitive). For transitive verbs the arithmetic commutativity of say + means that 2+3 is in every respect equal to 3+2. However when a computer does addition it is impossible for both arguments to be fetched simultaneously, and so, analogously with transitive verbs in English for which the subject is in some sense ‘stronger’ than the object, the left argument of dyadic verbs binds more strongly than the right. This becomes apparent when repetition is invoked by the power conjunction. Thus 2+^:(2)3 means add 2 twice to 3 (answer 7), as opposed to add 3 twice to 2 (answer 8).
Returning to punctuation, there are three verbs, all of infinite rank, which can be thought of as providing a ‘pseudo-punctuator’ role for verbs. These are (,) (append) (;) (link) and (,.) (stitch) In each example below the pseudo-punctuator is the middle tine of a fork, and the sum and difference of a list can be ‘pseudo-punctuated’ in the following ways
5 4(+,-)2 0 NB. sums joined to differences 7 4 3 4 5 4(+;-)2 0 NB. boxed sums, boxed differences ┌───┬───┐ │7 4│3 4│ └───┴───┘ 5 4 (+,.-)2 0 NB. sums, diffs as lists of lists 7 3 4 4
The verb ([) (left), also of infinite rank, provides pseudo-punctuation in the form of a statement separator
a=:2 [ b=.3 a,b 2 3
which works because the above line is essentially
with the assignment to b taking place ‘in passing’.
Square brackets can sometimes give rise to what looks orthographically as ‘verb parentheses’ when a transformation has to be applied to one argument only
2(*:@[+])3 7 2([+*:@])3 11
Arguably these phrases would have been written more clearly as 2((*:@[) + ])3 and 2([ + (*:@]))3 .
As the above example shows, redundant parentheses can be invaluable in clarifying the meanings of tacit definitions, although, like all good things, it can be overdone, and too many parentheses can sometimes be just as confusing as too few. Once a string of J symbols exceeds about seven characters even an expert reader's eyes begin to glaze over, as for example with
lengths=:<"1 @:,.3&":@:i.&' '"1
An example of using lengths might help to clear the fog
lengths >'Florida';'California';'Alaska' ┌─────────────┬─────────────┬─────────────┐ │Florida 7│California 10│Alaska 6│ └─────────────┴─────────────┴─────────────┘
Things become a little clearer if lengths is rewritten with some parentheses and an explicit space within the hook:
lengths1=:<"1 @: (,. ((3&":)@:(i.&' ')"1))
But following the seven character rule it would have been even better to articulate some of the bits by giving meaningful names to verbs along the following lines :
boxrows=:<"1 format=:3&": NB. width = 3 characters length=:(i.&' ')"1 NB. gives length of string lengths2=:boxrows@(,.(format@length))
Interestingly, although the above four lines appear at first sight to have only a few primitive symbols, all such symbols in lengths are faithfully reproduced. Arguably it would have been better to write lengths this way in the first place as this helps to contrast the multiple @: which define compound verbs, with the implicit punctuation in the hook ,.(format@length) .
Thoughtful punctuation can often help documentation. As a further example, most readers would find that on first sight the following verb definition conveys little of its purpose:
With some redundant parenthesising and renaming, and use of space to emphasise the fork, things become a little clearer :
sdest=:(+/@:(*:@:(-+/%#))) % (<:@#)
and with a little more renaming of the parts
sum=:+/ mean=:+/%# mdev=:-mean NB. mean deviation nminus1=:<:@# NB. n minus 1 sdest1=:sum@:(*:@mdev)%nminus1
the objective of providing the usual form of standard deviation estimate from a sample should become reasonably apparent.
When cap ([:) was introduced it was argued that it allowed indefinitely long trains of verbs to be written without parentheses, thereby implying that parentheses were inherently undesirable. The analogy in English is to favour long strings of words without punctuation, which may not be to everyone’s reading taste.
Forks and hooks work well enough because the human mind assimilates readily twosomes and threesomes, but thereafter the reverse is true, that is a b c d e wrongly suggests "a then b then c then …" whereas a b(c d e) gives a natural visual picture of the correct meaning. Continuing in the vein of the previous example *:-+/%# does not at first sight reveal its meaning whereas *:-(+/%#) says with reasonable clarity "subtract the mean from the squares".
A first step in the parser of most compilers and interpreters is to remove redundant spaces which are often highly desirable at the orthographic level, for example to underline the fact that three primitive verbs form a fork. Successive digraphs can lead the reader through an unnecessary initial step of disentanglement as, for example, in verb above which, even without the suggested parenthesising and breaking down into smaller verbs, would be easier to interpret if written
verb=:(+/@:*: @: - +/%#) % <:@#
that is, (add-following-square)-following-(mean-adjust) divide by decrement-tally. On the other hand spaces are probably best omitted between verbs and their objects, e.g. i. 5 is probably less clear than i.5, although it is best not to be too dogmatic.
mean=:+/ % # mean0=:(+/%#)"0 NB. scalarised mean verb=:(+/@:*:@:-+/%#)%<:@# sdest=:(+/@:(*:@:(-+/%#))) % (<:@#) sum=:+/ mdev=:-mean NB. mean deviation nminus1=:<:@# NB. n minus 1 sdest1=:sum@:(*:@mdev)%nminus1 lengths=:<"1 @:,.3&":@:i.&' '"1 lengths2=:boxrows@(,.(format@length)) boxrows=:<"1 format=:3&": NB. width = 3 characters length=:(i.&' ')"1 NB. gives length of string