Fifty Shades of J/Chapter 1
Table of Contents ... Glossary ... Next Chapter
Principal Topics
- & (compose) &. (under) @ (atop). β (rank conjunction) , fill characters, ragged arrays, heterogenous arrays, inner product.
Every and Each
In APL2 there was just one primitive symbol, double-dot (Β¨) for βeachβ β the βpepperβ effect is well imprinted on those with long memories, although that is not what APL looks like these days. In spite of J being considerably richer in primitives than APL, it does not include βeachβ as a primitive. Instead J recognizes that there are two types of βeachβ, both defined as adverbs in the standard vocabulary and both using Open (>)
every=.&> NB. uses compose each=.&.> NB. uses under
The definitions of the conjunctions & and & giving rise to the verbs u∧v and u&.v in mathematical terms as (uv) and (vβ»ΒΉuv) show that the rule:
(f every) -: >@(f each)
is completely general, and so only one of βeachβ and βeveryβ is ever logically necessary. βeachβ has the general merit of greater compactness through generating what APL2 users would recognise as ragged arrays. On the other hand βeveryβ has the merit of avoiding, or at least reducing, boxing on display, but often at the expense of requiring greater numbers of fill characters to achieve global homogeneity. In writing J it can be handy to have a βrule of thumbβ appreciation of how βeachβ and βeveryβ work without having to consider the semantic details of box and open at every point of use. Thinking in terms of lists is helpful in using βeachβ and βeveryβ effectively, as is sensitivity to the ways in which argument rank works. J has a wealth of algorithms pre-implemented for its users within its interpreters. Effective use of these requires an understanding that Data = Values + Structure and that βeachβ and βeveryβ allow algorithms to apply to different levels of the structure. For example, given
h=.i.2 3 NB. two 3-lists, rank = 2
compare the following
h,every 6 7 NB. one 2-list, items=3 2-lists, rank=3 0 6 1 6 2 6 3 7 4 7 5 7 h,each 6 7 NB. 2 3-lists, items=2-lists, rank=2 βββββ¬ββββ¬ββββ β0 6β1 6β2 6β βββββΌββββΌββββ€ β3 7β4 7β5 7β βββββ΄ββββ΄ββββ
Applying the general rule above h,every 6 7 is identical to >h,each 6 7, or to put it in another way, the two displays above show the same six 2-lists, in one case individually boxed, in the other integrated into a structure of higher rank.
Using either 'each' or 'every' with a dyadic verb often requires the user to box one of the arguments to achieve a desired result through bringing about correct argument matching. Often this consists of a simple boxing of one of the arguments as in:
x=.6 7;8;9 10 11 12 (<h),each x NB. left rank 0, right rank 1, result rank 1 βββββββ¬ββββββ¬βββββββββββ β0 1 2β0 1 2β0 1 2 0β β3 4 5β3 4 5β3 4 5 0β β6 7 0β8 8 8β9 10 11 12β βββββββ΄ββββββ΄βββββββββββ
The result is a 3-list of scalars (and so of rank 1) each made from the same scalar (<h) joined to each item of a 3-list, with everything opened and boxed following the (vβ»ΒΉuv) rule which defines &. (under). There is a local fill character in the first box, a local scalar expansion in the second, and the third containing two fill characters in the final column has a different shape ($) from the other two. Compare this with:
(<h),every x NB. left rank 0, right rank 1, result rank 3 0 1 2 0 3 4 5 0 6 7 0 0 0 1 2 0 3 4 5 0 8 8 8 0 0 1 2 0 3 4 5 0 9 10 11 12
where there is no vβ»ΒΉ boxing. Again the result is a 3-list, but now not of scalars but of three filled lists, each of which is a 4-list of scalars after filling. APL2 talked about βraggedβ and βheterogeneousβ arrays β a more appropriate differentiation in J is between locally- and globally-filled lists, corresponding to each and every. Using "0 as an alternative gives a result rank between those of every and each :
(<h),"0 x NB. left rank 0, right rank 1, result rank 2 βββββββ¬βββββββββββ β0 1 2β6 7 β β3 4 5β β βββββββΌβββββββββββ€ β0 1 2β8 β β3 4 5β β βββββββΌβββββββββββ€ β0 1 2β9 10 11 12β β3 4 5β β βββββββ΄βββββββββββ
Here the scalar left argument gives rise to scalar replication, and the result is a 3-list of non-homogeneous 2-lists without fill characters, that is, it is only the display which is rectangular not the result object itself, as is made explicit by
$each (<h),"0 x βββββ¬ββ β2 3β2β βββββΌββ€ β2 3β β βββββΌββ€ β2 3β4β βββββ΄ββ
In order to avoid monotonous repetition, subsequent examples will use just one of each or every, the other case being covered by the general rule (f every) -: (>f each) . Consideration of rank is almost always a preliminary to well-considered usage of each. There are no overall rank rules because these depend on the semantics of each individual f . In the next set of examples three figures in square brackets in a comment give the left, right and result ranks of the verb |. or |.each .
Consider first the basic case of the verb Rotate (|.) with a rank 1 argument on the left and a rank 2 argument on the right:
0 1|.h NB. 0-rotate rows ,: 1-rotate cols [1 2 2] 1 2 0 4 5 3
Applying each with box on either right or left changes the ranks:
0 1 |.each <h NB. 0-rotate on h ; 1-rotate on h [1 0 1] βββββββ¬ββββββ β0 1 2β3 4 5β β3 4 5β0 1 2β βββββββ΄ββββββ (<0 1)|.each h NB. (<0 1)-rotate on items of h [0 2 2] βββ¬ββ¬ββ β0β1β2β βββΌββΌββ€ β3β4β5β βββ΄ββ΄ββ
Between these extremes is the possibly more useful case of βleft rank 1, right rank 1β:
0 1|.each<"1 h NB. 0-rotate 1st row;1-rotate 2nd [1 1 1] βββββββ¬ββββββ β0 1 2β4 5 3β βββββββ΄ββββββ
Next, given the laminated rank 3 object:
]hlam=.(i.2 3),:10+i.2 3 0 1 2 3 4 5 10 11 12 13 14 15
here are the effects of four rather similar expressions, along with annotated descriptions which attempt to explain the differences between them. What is the best medium for such descriptions? Why J, of course, hence the comments which follow each of the four executable lines supply matching equivalent statements
(<0 1)|.each <"2 hlam NB. (0 1|.h);(0 1|.h+10) [0 1 1] βββββββ¬βββββββββ β1 2 0β11 12 10β β4 5 3β14 15 13β βββββββ΄βββββββββ 0 1|. each <"2 hlam NB. (0|.h);(1|.h+10) [1 1 1] βββββββ¬βββββββββ β0 1 2β13 14 15β β3 4 5β10 11 12β βββββββ΄βββββββββ 0 1|. each <"1 hlam NB. (0|. each H<"1 h),:(1|. each <"1 h+10) ββββββββββ¬βββββββββ β0 1 2 β3 4 5 β ββββββββββΌβββββββββ€ β11 12 10β14 15 13β ββββββββββ΄βββββββββ
This example is also equivalent to 2 2$0 0 1 1|. each H,<"1 hlam , since ,<"1 hlam is a 4-list whose items are 3-lists such as 0 1 2.
The next example illustrates how "0 means apply a rotate at the scalar level which is necessarily a βdo nothingβ operation.
(0 1)|."0<"2 hlam NB. equivalent to <"2 hlam [1 1 1] βββββββ¬βββββββββ β0 1 2β10 11 12β β3 4 5β13 14 15β βββββββ΄βββββββββ
A further set of examples illustrates what happens with characters. g is a pair of 2-lists and thus has the same shape as h, only its items are characters lists rather numbers.
]g=.2 3$'ant';'bee';'cat';'dog';'elk';'frog' βββββ¬ββββ¬βββββ βantβbeeβcat β βββββΌββββΌβββββ€ βdogβelkβfrogβ βββββ΄ββββ΄βββββ
Where items are characters lists, there are necessarily possible ambiguities between genuine space characters and space fill characters, something which is clarified in
1 |. each g NB. 1-rotate items ranks=[0 2 2] βββββ¬ββββ¬βββββ βntaβeebβatc β βββββΌββββΌβββββ€ βogdβlkeβrogfβ βββββ΄ββββ΄βββββ
The next example shows simultaneous opening of both arguments followed by vβ»ΒΉ boxing:
(<0 1)|. each <g NB. <0 1|.g, ranks=[0 0 0] ββββββββββββββββ ββββββ¬βββββ¬βββββ ββbeeβcat βantββ ββββββΌβββββΌββββ€β ββelkβfrogβdogββ ββββββ΄βββββ΄βββββ ββββββββββββββββ
The next example is one in which the result rank is less than an argument rank:
0 1|. each <g NB. (<0|.g),(<1|.g),ranks=[1 0 0] ββββββββββββββββ¬βββββββββββββββ ββββββ¬ββββ¬βββββββββββ¬ββββ¬ββββββ ββantβbeeβcat βββdogβelkβfrogββ ββββββΌββββΌβββββ€ββββββΌββββΌβββββ€β ββdogβelkβfrogβββantβbeeβcat ββ ββββββ΄ββββ΄βββββββββββ΄ββββ΄ββββββ ββββββββββββββββ΄βββββββββββββββ
the final example in this set the shapes of the items within the two outer boxes are not identical, thus resolving an ambiguity between fill- and genuine space characters which each would not have shown:
0 1|. each <"1 g NB.(<0|.0{g),(<1|.1{g),ranks=[1 1 1] βββββββββββββββ¬βββββββββββββββ ββββββ¬ββββ¬ββββββββββ¬βββββ¬βββββ ββantβbeeβcatβββelkβfrogβdogββ ββββββ΄ββββ΄ββββββββββ΄βββββ΄βββββ βββββββββββββββ΄βββββββββββββββ
However, given that each by definition reduces one level of boxing in every case, it often gives less fussy-looking results than each where character lists are involved.
The examples so far have been chosen to illustrate the principles of each and every. An example of a practical problem involving each is that of evaluating linear expressions such as x + 2y - z over separate ranges of values of their variables. The results in this simple example are easy to check.
t3=.1 2;3 4 5;6 NB. x={1,2} y={3 4 5} z={6} {t3 NB. catalog gives all combinations βββββββ¬ββββββ¬ββββββ β1 3 6β1 4 6β1 5 6β βββββββΌββββββΌββββββ€ β2 3 6β2 4 6β2 5 6β βββββββ΄ββββββ΄ββββββ ip=.+/ .* every NB. 6 inner products with 1 2 _1 ({t3)ip <1 2 _1 1 3 5 2 4 6 ip=.+/ .* each ({t3)ip <1 2 _1 βββ¬ββ¬ββ β1β3β5β βββΌββΌββ€ β2β4β6β βββ΄ββ΄ββ
The advent of βeachβ (Β¨) and ragged arrays in APL2 breathed new life into that language. J deals with such matters more subtly by forcing choices between the two possibilities βeachβ or βeveryβ. In broad terms each allows raggedness and reduces homogeneity to a local level, every reduces boxing at the cost of imposing greater homogeneity through globally applied fill characters.
Code Summary
every=.&> each =.&.> ip=.+/ .*