An Elementary Tutorial on Conjunctions
Vector 18:2, page 64
Transcribed from the printed issue; not yet reviewed. Read it in the PDF of the issue, page 64
Introduction¶
J is an Executable Mathematical Notation, which explains J’s conciseness, completeness, and consistency. This is the source of J’s power and the reason for its appeal. J’s elements are nouns, verbs, adverbs, and conjunctions. Commonly: nouns are items of data; verbs (mathematical functions) take either one or two noun arguments and have noun results; adverbs take a single (left) argument – usually a verb – and have a verb result; and conjunctions (mathematical operators) have two arguments (either nouns or verbs) and have verb results. J also supports the creation of new verbs, adverbs, and conjunctions by composition of functions, based on either conjunctions or trains of elements. The 25 possible tridents and the 12 possible bidents are listed in the J Dictionary II F. This tutorial illustrates 12 tridents and 4 bidents.
New users quickly learn how to define a verb and how to use adverbs and conjunctions, but it is less well known that users can define their own adverbs and conjunctions. Brian M. Schott (Georgia State University)recently asked me for an illustration, and this tutorial (which developed from my reply), shows how to read and write both explicit and tacit definitions. Brian cited articles posted to the c.l.a Newsgroup in October 1992, and the first of these is my starting point.
In a paper on "The Role of Composition in Computer Programming" I discussed defined adverbs and conjunctions; e.g. plotting one monadic function against another (APL95 Proceedings. See http://homepage.ntlworld.com/donald.mcintyre for a pdf version). "A conjunction can be used when an expression containing two verbs is generalized so that other verbs can be substituted. Defined adverbs and conjunctions are miniature computer programs with both verb and noun arguments."
This tutorial is intended to be read – and, where appropriate, executed – after reading the Dictionary II E (Parsing and Execution) and II F (Trains). The pages should be open for reference to the tables of tridents and bidents in II F.
Keep in mind that (a) execution proceeds from right to left except where modified by parentheses; (b) a conjunction’s left argument is the entire verb phrase that precedes it, and its right argument is the item immediately to its right; and (c) adverbs and conjunctions are executed before verbs.
I hope that what follows helps users to understand better ‘how J works’.
Conjunctions in 1992¶
In October 1992, at Ken Iverson’s invitation, I gave J workshops in London (UK), Toronto, Waterloo (ONT), Lawrence (KS), Claremont (CA), San Jose (CA), Dallas (TX), Phoenix (AZ), Washington (DC), and Wooster (OH). On 1992 10 21 J. Patrick Harrington (Astronomy, U. of Maryland) sent the first of a series of interesting messages on J to the comp.lang.apl Newsgroup. He referred to these messages as his "musings". His title was: "Tacit numerical integration?"
The conjunction D. was implemented in J Version 6.2, 1992 12 20; i.e. two months after my Workshop in Washington. Using D. we can show that the first derivative of the sine is the cosine:
Note that D. is a conjunction, which with its noun right argument (1) is an adverb, here modifying the verb sin.
class=: 4!:0
C=: D. NB. Conjunction Valence 2
A=: D.1 NB. Adverb Valence 1. CO N1 is x CO N1 (bident II F p.103)
class ;/'CA'
2 1
In his message on 21 Oct 1992 Patrick Harrington wrote:
"On the Oct 10-11 weekend, Donald McIntyre gave two fine workshops on J here in Washington, which I found both interesting and useful. As is usual with J, many new questions sprouted, Hydra-like, as the old ones were lopped off. One bit I found interesting was the use of ]. and [. to construct conjunctions. Thus he showed that
is a conjunction. If we let h be a small number, say h=. 1e_8 , then the expression (h D) is an adverb such that for a function (verb) f which applies to a noun n,
is the approximate derivative (f(n+h)-f(n))%h.
e.g.,
f=. 1&o. NB. f is sin(n)
] n=. 0.1*(i. 7)
0 0.1 0.2 0.3 0.4 0.5 0.6
f (h D) n
1 0.995004 0.980067 0.955336 0.921061 0.877583 0.825336
2 o. n
1 0.995004 0.980067 0.955336 0.921061 0.877583 0.825336
This makes me think that one should be able to construct a conjunction X such that f (h X) n would take one step of Runga-Kutta integration, say, from x to x+h, where the function f describes the differential equation. … "
Others can deal better than I can with what Patrick Harrington went on to discuss, but I concentrate on the conjunction that started his train of thought; namely:
Remembering Whitehead’s remark that "nothing is more incomprehensible than symbolism we do not understand", let’s remove the mystery from what may appear a forbidding expression.
f=: 1&o. NB. sin
'h n'=: 1e_8; 0.1 * i.8
class 'h';'n';'f';'D' NB. 2 nouns, a verb, and a conjunction
0 0 3 2
With a step of h, the approximate derivative of f at n is given by:
]z=: ((f n+h) - f n) % h NB. Immediate execution
1 0.9950041652 0.9800665779 0.9553364877 0.9210609886 0.8775825622 0.8253356
11 0.7648421896
Writing this as z-: %&h ((f n+h)- f n) already removes some of the mystery from D because the similarity between the two expressions is not hard to find:
The result is the quotient of two quantities. This suggests the fork trident numerator % denominator, analogous to mean=: +/ % # (the mean is the sum of the items divided by the number of items).
The numerator ((f n+h) - f n) is easily recast as a fork:
A fork, however, is a trident of three verbs (V0 V1 V2), and in our case the denominator (h) is a noun. We need, therefore, a verb that returns the constant h whatever its argument, and such a verb is created by the rank conjunction:
h"_ (N0 C1 N2 is a verb). I have not found in the Status Reports a record of its introduction, but it was supported in J Version 7, 1993 11 14. If, indeed, it was not supported in J 5.1, 1992 7 28, this would explain why the D conjunction used in the Workshop took the form ([.(%&))@(f@+&h - f) instead of the fork (f@+&h - f) % h"_ It is more likely, however, that in October 1992 I had not yet learned how to use the feature.
Explicit Definition¶
We need a conjunction combining h and f to make a verb; we could then use this verb with argument n. The required conjunction is easily constructed using explicit definition (Dictionary p.153-156, p.106-107; Phrases p.20-24). In Ken Iverson’s words:
"All that is needed to understand the explicit form is the pattern:
where x. and y. are the arguments of the function produced by the conjunction, and where u. and v. are its arguments (possibly replaced by m. and n. to restrict them to nouns)."
Replace f h and n by v. m. and y. respectively. (In our case there is no x. .)
Reference to the arguments x. and y. is explicit. Note how explicit definition parallels immediate execution:
z=: (( f n + h ) - f n ) % h NB. Immediate execution
ve=: 3 : '(( f n + h ) - f n ) % h' NB. Verb (explicit)
ce=: 2 : '(( v. y.+ m.) - v. y.) % m.' NB. Conjunction (explicit)
The explicit verb ve is included only to emphasize the parallelism between verb and conjunction. J does not support niladic verbs; the verb ve takes but ignores its argument.
z-: ve 3.14
z-: (h ce f) n NB. verb Parentheses redundant
z-: f (h ce) n NB. adverb Parentheses required
To save space, the 1 resulting from all instances of z-: will be omitted.
The parentheses in (h ce f) n are redundant. This is because the conjunction takes f as its right argument, thus effectively introducing a right parenthesis between f and n. Parentheses merely draw attention to a phrase which creates a verb.
Parentheses in f (h conj) n are required. The phrase N0 C1 creates an adverb. Without parentheses, n would be the conjunction’s right argument.
Explicit definitions can be written in an alternative form without quotation marks:
ce=: 2 : 0
(( v. y.+ m.) - v. y.) % m.
)
v=: h ce f NB. verb N0 C1 V2
a=: h ce NB. adverb N0 C1
class 'v';'ce';'a' NB. verb conjunction adverb
3 2 1
z-: v n
z-: f a n
Tacit Definition¶
Unlike explicit definition, tacit definition makes no direct reference to the arguments (x. and y.) of the resulting function.
V0 C1 V2 is a verb; e.g. (f @ +) and (f @ ]) These are not forks!
V0 V1 V2 is a verb; g illustrates this trident; g is a fork.
Remember: A trident is a fork only if all three components are verbs!
f@+ applies f to the sum of its two arguments
f@] applies f to its right argument alone
z-: (h g n) % h NB. (n v n) is n
z-: ((f n + h) - f n) % h NB. Immediate execution
vt1=: (f@ (+&h) - f) % h"_ NB. Tacit verb
vt2=: (f@ +&h - f) % h"_ NB. Only required parentheses
hv=: h"_ NB. n c n A "constant" verb yielding h
class 'h';'hv';'vt1';'vt2' NB. noun and 3 verbs
0 3 3 3
f@+&h is the train v c v c n. Because a conjunction takes the item immediately to its right as its right argument, the train is parsed ((v c v) c n). This is demonstrated by a simple model:
Because both (v c v) and (v c n) are verbs, the result is (v - f), which is a fork (V0 V1 V2).
h"_ is a verb (N0 C1 N2), consequently vt2 is a train of three verbs and is therefore another fork.
The distinction between verbs and conjunctions must not be overlooked!
left=: [ NB. verb
right=: ] NB. verb
lev=: [. NB. conjunction
dex=: ]. NB. conjunction
class 'left';'right';'lev';'dex'
3 3 2 2
In a tacit definition the u. and v. of an explicit definition are replaced by the conjunctions [. and ].
Note the parallelism of the following:
z-: ((f n + h ) - f n ) % h NB. Immediate execution
ce=: 2 : '((v. y.+ m.) - v. y.) % m.' NB. Conjunction (explicit y.)
vt=: ( f @ +&h - f ) % h"_ NB. Verb (tacit reference to y.)
ct=: ( ].@ +&[. - ].) % ([."_) NB. Conjunction (tacit)
Although all four are based on the paradigm (numerator % denominator), only vt and ct are (V0 V1 V2) tridents; i.e. forks. In tacit forms the noun h in the right tine is replaced by the (n c n) verb (h"_), or by the (c c n) conjunction ([."_). Parentheses prevent [. taking % as its left argument. Because h"_ is a verb, parentheses are not needed.
The left tine of vt is (v c v c n v v) or (((v c v) c n) v v)
or ((v c n) v v) or (v v v) or v, which is a fork.
Consequently vt is v % h"_ or v v (n c n) or v v v
The left tine of ct:
A simple model shows how this is parsed:
The parenthesized display of ct looks like a fork, but this is misleading.
The pieces are:
w1=: ].@+ NB. c c v or c
w2=: w1&[. NB. c c c or c
w3=: w2 - ]. NB. The left tine c v c or c This is not a fork!
w4=: [."_ NB. c c n or c
w=: w3 % w4 NB. c v c or c
class 'ct';'w1';'w2';'w3';'w4';'w' NB. All are conjunctions
2 2 2 2 2 2
z-: h w f n
z-: vt n NB. verb
z-: (h ce f) n NB. verb. Parentheses redundant
z-: (h ct f) n NB. verb. Parentheses redundant
z-: f (h ct) n NB. adverb
(h"_ + ]) is a fork because h"_ + and ] are verbs, hence v v v
z1=:f@(h"_ + ]) n
c1=: ].@([."_ + ])
c1
]. @ ([. " _ + ])
c c ((c c n) v v) or c c (c v v) or c c c or c
@ @ (@ @ 3 + +)
@ @ ((@ @ 3) + +)
z1-:h c1 f n
z2=: (f@ ( h"_ + ])- f) n NB. Fork whose left tine contains a fork
c2=: ].@([."_ + ]) - ]. NB. No forks. [."_ is a conjunction
c c (c v v) v c
@ @ (@ + +) + @
(@ @ (@ + +)) + @
(@ @ @) + @
@ + @
@
z2-: h c2 f n
c3=: c2 % ([."_) NB. c v c Not a fork. Parentheses required.
z-: h c3 f n
c4=: (].@([."_ + ]) - ].) % ([."_)
z-: h c4 f n
(((]. @ +) & [.) - ].) % ([. " _)
Ce=: 2 : '(y.@(x."_ + ]) - y.) % x."_' NB. x."_ must be a verb for (v v v)
z-: h Ce f n
Evoke Gerund: Dictionary p.201¶
"Evoke gerund" is another way of creating a conjunction. We need to combine two functions: (a) the difference between (f (h+n) - f h), and (b) division by h.
As the Dictionary explains: "Caps make it possible to define a wider range of functions as unbroken trains." The verb [: normally caps a left branch of a fork (V0 V1 V2)
x1 and x2 are conjunctions which generate verbs when associated with the arguments h and f.
A fork (V0 V1 V2) yields a verb, whereas ct2 is C0 C1 C2, and
ct3 is v c c c c c which is ((v c c ) c c) or c c c which yields a conjunction.
Tacit Translator¶
C1=: 12 : '(y.@(x."_ + ]) - y.) % x."_'
z-: h C1 f n
1
C1
((]. @ (([. " _) + ])) - ].) % ([. " _)
ct NB. Linear
(((]. @ +) & [.) - ].) % ([. " _)
ct=: (].@+&[. - ].) % ([."_) NB. Only required parentheses
The classes of the elements of this train of conjunctions and verbs are:
Processing of ct is from right to left. Each conjunction ‘grabs’ the item to its right. Phrases in parentheses are evaluated first.
Notes¶
"Parsing proceeds by moving successive elements … from the tail end of a queue … to the top of a stack. … The executions in the stack are confined to the first four elements only, and eligibility for execution is determined only by the class of each element …, as prescribed in the parse table on p.101." [Dictionary II E]
"Because conjunctions have long left-scope and short right-scope, the phrase 5!:4@< (noun conjunction noun conjunction verb) parses as ((n c n) c v), which in turn resolves into (v c v), and finally to verb. … Although execution proceeds from right to left, a sequence of verbs [and nouns] joined by conjunctions is parsed as if parenthesized from left to right. The consequences of this are easily overlooked. When in doubt, consult the boxed display and [if need be] use parentheses to control the desired order of execution." [The Role of Composition in Computer Programming, APL95 Proceedings]
c c v c c v c is therefore parsed by taking the final c c v c into the stack. The final triad c v c is not executed because it is preceded by a conjunction which grabs the leftmost c of the triad so that the initial result is c c ) c v.
Proceeding in this manner from right to left, the parenthesized result is:
((c c v) c c) v c . Although the sentence is indeed parsed from right to left, the sequence of execution is modified by these implied parentheses. Thus,
(c c v) is c and (c c c) v c is C0 V1 C2 which in turn is c.
As this point is often misunderstood by a user encountering a train with conjunctions, it is necessary to understand the implications of the following statement: "Execution proceeds from right to left, except that when a right parenthesis is encountered, the segment enclosed by it and its matching left parenthesis is executed, and its result replaces the entire segment and its enclosing parentheses." (Dictionary II E item 1.)
It is also helpful to observe the parsing by using the trace conjunction 13!:16 (See Dictionary p.100, 285).
A simple test for our example is to enter and display a model of the train; e.g.
NB. (c c v c c v c ) v (c c n)
(@ @ + @ @ + @ ) + (@ @ 3)
(((@ @ +) @ @) + @) + (@ @ 3)
z-: ((f n+h) - f n) % h NB. Immediate execution
If you can write a 2 : x definition of a conjunction using x. and y. without reference to u. and v., thus:
then the conjunction can be automatically translated to tacit style, thus:
Note that in Ce x."_ does not need parentheses. The translator recognises forks by our use of parentheses and by our making x. into a verb (i.e. x."_ )
Attempting to justify those parentheses that are required is a useful exercise; e.g.
Use these models to clarify how the parsing rules work:
@ @ @ @ 3 + + + @ + @ @ 3
(((@ @ @) @ 3) (+ + +@+) @) @ 3
(@ @ (@ @ 3 + +) + @) + (@ @ 3)
((@ @ ((@ @ 3) + +)) + @) + (@ @ 3)
Finally, when examining tree and box displays be careful to avoid interpreting every trident as a fork:
Concluding Remarks¶
In a brief response to Patrick Harrington on 1992 10 23 I said: "Everything of significant merit that I disclosed is due to Ken Iverson (e.g. the conjunction D) or Roger Hui. I simply put some of their gems in a context that I found satisfying."
I should state that this is still true.
The next day Roger referred to what Patrick called his ‘monolog’, and particularly to this comment by Patrick on tacit definition:
"I would like a conjunction X so that (h X) is an adverb, and f (h X) n is the integration step. And of course, in tacit form. This is supposed to be a *good thing*, although just why this is so is not yet clear to me."
Roger’s response to Patrick’s implied question included the following points:
"Some advantages are:
0) The tacit form encourages the use of components, primitive and user-defined. Use of components is one of the few effective ways of dealing with complexity.
1) The tacit form focuses on how components are combined, i.e. it focuses on the interface between components, where errors tend to occur.
2) Tacit expressions are algebraic, i.e. they are amenable to proof and other formal manipulations.
3) Tacit expressions are constructed using operators (adverbs and conjunctions), ideas debugged in mathematics over hundreds of years."
But it strikes me that a fourth order Runge-Kutta formula in tacit J could be a very ugly beast. And this is a concern, that on any non-trivial problem, finding the tacit forms may be too hard to be worthwhile. [JPH]
"I do not believe it is necessarily ugly, at least not if there is judicious use of well-chosen subfunctions. " [RH]
Ken Iverson gave me the following advice:
"I don’t think it wise to strive too hard to write tacit definitions for conjunctions: it is not always possible, and it is almost always much more difficult to understand than the explicit form."
"During the period of design I did all I could to use only the tacit form, because this tested the possibilities and led to new forms (such as f conj to define an adverb). Now I feel more relaxed about using the explicit form, even for verbs (although the use of the tacit form may lead to simple structuring, as in k=: f @ (g+h), with subsequent definition of the components)."
Roger Hui recently made the following comments to me regarding his preference for explicit or tacit definitions:
"I myself would use whatever form is clearer and more effective, and that may be tacit in some cases and explicit in others. For myself, adverbs and conjunctions are more often clearer in the explicit form."
And further:
"A rule of thumb that I find helpful: If I can not write a conjunction (adverb) without resorting to the explicit form that uses both x. y. and u. v. (and/or m. n.), then probably the conjunction should not be written tacitly (much too complicated to easily understand)."
"If the conjunction uses only x. and y. (i.e. only the operator arguments and not also the derived verb arguments), that means the conjunction produces a result (the derived verb) which is tacit, and I believe (I need to prove this) there is an automatic procedure to convert such a conjunction to tacit form. (12 : x is this automatic procedure.) As well, the result of this automatic procedure is not too convoluted for my brain to grasp."
Acknowledgements¶
Thanks to Brian Schott for posing the question and reminding me of Patrick Harrington’s "musings"; to Patrick for responding to the 1992 workshop; to Keith Smillie for suggestions and encouragement; and to Ken Iverson and Roger Hui for making all this possible, for many patient explanations, and for permission to quote their very helpful advice and observations. Remaining errors are mine, and I would appreciate receiving comments and corrections.
Points that may be of insufficient general interest to post on J Forum can be sent to me.
Footnote¶
After my tutorial on the definition of new conjunctions was posted on the J Forum, John Wilson asked a related question: "(Why) are the expressions (functions) f@(+&h) and (f@+)&h equivalent? "
Henry Rich correctly replied that "for a function f that has different behavior when applied at rank 0 and rank _, the expressions are not equivalent. … If @: were used in place of @, the expressions would be equivalent. For the actual f that was used, they are equivalent."