Chapter 12: Explicitly Defined Operators
This chapter covers explicit definition of operators, that is, adverbs and conjunctions defined with the colon conjunction. The scheme is:
1 : body is an adverb 2 : body is a conjunction
where body is one or more lines of text. The possibilities for the result produced by an operator are: a tacit verb, an explicit verb, a noun or another operator. We we will look at each case in turn.
12.1 Operators Generating Tacit Verbs
Recall from Chapter 07 the built-in rank conjunction ". For any verb u, the expression u"0 is a verb which applies u to the 0-cells (scalars) of its argument.
Now suppose we aim to define an adverb A, to generate a verb according to the scheme: for any verb u
u A is to be u " 0
Adverb A is defined explicitly like this:
In the definition (A =: 1 : 'u. " 0') the left argument of the colon is 1, meaning "adverb".
The right argument is the string 'u. " 0'. This string has the form of a tacit verb, where u. stands for whatever verb will be supplied as argument to the adverb A.
Adverbs are so called because, in English grammar, adverbs modify verbs. In J by contrast, adverbs and conjunctions in general can take nouns or verbs as arguments. In the following example, adverb W is to generate a verb according to the scheme: for integer u
u W is to be < " u
that is, u W boxes the rank-u cells of the argument. The definition of W is shown by:
For another example of an adverb, recall the dyad # where x # y selects items from y according to the bitstring x.
To select items greater than 0, we can apply the test-verb (>&0)
A tacit verb to select items greater than 0 can be written as a fork f:
This fork can be generalised into an adverb, B say, to generate a verb to select items according to whatever verb is supplied in place of the test >&0.
B =: 1 : 'u. # ]'
If we supply >&1 as a test-verb:
We see that the body of B is the fork to be generated, with u. standing for the argument-verb to be supplied.
Conjunctions, taking two arguments, are defined with (2 : '...'). The left argument is u. and the right is v.
For example, consider a conjunction THEN, to apply one verb and then apply another to the result, that is, a composition. The scheme we want is:
u THEN v is to be v @: u
and the definition of THEN is:
For another example, consider counting (with #) those items of a list which are greater than 0. A verb to do this might be:
We can generalize foo to apply a given verb u to items selected by another given verb v. We define a conjunction C with the scheme
NB. u C v is to be u @: (v # ])
and the definition of C is straightforwardly:
12.1.1 Multiline Bodies
The right argument of colon we may call the body of the definition of our operator. In the examples so far, the body was a string, a schematic tacit verb, for example 'v .@: u.' . This is the verb to be delivered by our operator. More generally, the body can be several lines. The idea is that, when the operator is applied to its argument, the whole body is executed. That is, each line is evaluated in turn and the result delivered is the value of the last line evaluated. This is exactly analogous to explicit verbs, except that here the result is a value of type "function" rather than of type "array".
Here is an example of a multi-line body, the previous example done in two steps. To apply u to items selected by v, a scheme for conjunction D could be written:
u D v is to be (u @: select) where select is v # ]
and D defined by
D =: 2 : 0 select =: v. # ] u. @: select )
Again counting items greater than 0, we have
The first line of D computes an inner function select from the right argument. The second line composes select with the left argument, and this is the result-verb delivered by D.
Now this definition has an undesirable feature: we see that select is defined as a global (with =:). It would be better if select were local.
However, we can see, by looking at the value of the verb f above, that select must be available when we apply f. If select is local to D, it will not be available when needed.
We can in effect make select local by using the "Fix" adverb (f.) (letter-f dot.) The effect of applying "Fix" to a verb is to produce an equivalent verb in which names are replaced by by their corresponding definitions. That is, "Fix" resolves a tacit verb into its primitives. For example:
Here is how we use Fix to enable select to be local. In the example below, notice that we Fix the result-expression on the last line:
E =: 2 : 0 select =. v. # ] (u. @: select) f. )
Now a verb to count greater-than-0 items can be written:
We see that g, unlike f, has no local names.
12.2 Explicit Operators Generating Explicit Verbs
12.2.1 Adverb Generating Monad
Consider the following explicit monadic verb, e. It selects items greater than 0, by applying the test-verb >&0.
We can generalise e to form an adverb, F say, which selects items according to a supplied test-verb. The scheme we want is: for any verb u:
u F is to be 3 : '(u y). # y.'
Adverb F is defined by:
F =: 1 : '(u. y.) # y.'
Now the verb >&1 F will select items greater than 1:
In the body of F the variable u. stands for a verb to be supplied as argument to adverb F. If this argument is say >&1, then y. stands for an argument to the generated explicit verb 3 : '(>&1 y.) # y.'.
That is, our method of defining the generated verb is to write out the body of an explicit definition, with u. at places where a supplied verb is to be substituted.
12.2.2 Conjunction Generating Monad
A conjunction takes two arguments, called u. and v.. Here is an example of a conjunction to generate an explicit monad.
As before, we specify the generated verb, by writing out the body of an explicit verb. Here y. stands for the argument of the generated verb and u. and v. stand for argument-verbs to be supplied to the conjunction. In this example the body is multi-line. As before, u. will be applied to items selected by v.
G =: 2 : 0 selected =. (v. y.) # y. u. selected )
Now a verb to count greater-than-zero items can be written as # G (>&0):
12.2.3 Generating a Dyad
For the next example, let us define a conjunction generating an explicit dyad. Suppose we want a conjunction H such that, schematically,
u H v is to be 4 : '(u x.) + (v y.)'
Now it is a fact that all the generated verbs are defined in terms of 3 :, not 4 :. We can write a dyad with 3 : by beginning a multi-line body with the solo colon which separates the monadic case from the dyadic.
Thus, schematically, we have to say, for verbs u and v:
u H v is to be 3 : 0 : (u x.) + (v y.) )
The explicit definition of H follows straightforwardly:
H =: 2 : 0 : (u. x.) + (v. y.) )
So far, we have seen that for operators introduced with 1 : or 2 :, there are two kinds of definition.
If we have ONLY u. or v. or both, then the generated function is tacit.
If we have BOTH (u. or v.) AND (x. or y.) then the generated function is explicit.
On this basis, the cases we have considered are:
1 : '.. u. ..' tacit-generating adverb
12.2.5 Alternative Names for Argument-Variables
The arguments to operators may be nouns or verbs. There is a way of constraining arguments to be nouns only, that is, to cause verbs to be signalled as errors. To impose the constraint, we write the argument-variables as m. and n. rather than as u. and v.. For example, without the constraint we could write:
With the constraint we write:
We said above that with ONLY u. or v. or both occurring as argument variables, we get a tacit verb generated. For the sake of completeness, we should add m. and n. to this list.
Furthermore, if the only argument variables are x. or y. or both, we get a tacit verb, not an explicit verb. That is, in the absence of u. or v. or m. or n. then x. and y. are equivalent to u. and v..
12.2.6 Executing the Body (Or Not)
To demonstrate when the body gets executed (or evaluated), we can use a utility verb which displays its argument on-screen:
display =: (1 !: 2) & 2
Now insert display 'hello' into a tacit-generating operator:
R =: 2 : 0 display 'hello' select =. v. # ] (u. @: select) f. )
When R is applied to its argument, the body is demonstrably executed:
f =: # R (>&0) hello f 1 0 2 0 3 3
By contrast, if we do the same with an explicit-generating operator:
S =: 2 : 0 display 'hello' selected =. (v. y.) # y. u. selected )
we see that the body of S is NOT executed when the operator is applied to its argument: but it IS executed when the generated verb g is applied.
g =: # S (>&0) g 1 0 2 0 3 hello 3
12.3 Operators Generating Nouns
Operators can generate nouns as well as verbs. Here is an example.
A fixed point of a function f is a value p such that (f p) = p. If we take f to be
f =: 3 : '2.8 * y. * (1-y.)'
then we see that 0.642857 is a fixed-point of f
f 0.642857 0.642857
Not every function has a fixed point, but if there is one we may be able to find it by repeatedly applying the function (with ^: _) to a suitable starting value. A crude fixed-point-finder can be written as an adverb FPF which takes the given function as argument, with 0.5 for a starting value.
12.4 Operators Generating Operators
Here is an example of an adverb generating an adverb.
First note that (as covered in Chapter 13) if we supply one argument to a conjunction we get an adverb. The expression (@: *:) is an adverb which means "composed with square". To illustrate:
Now back to the main example of this section. We aim to define an explicit adverb, K say, which generates an adverb according to the scheme: for a verb u
u K is to be @: u
Adverb K can be defined as below. We see that adverb K delivers as a result adverb L:
This is the end of Chapter 12.
Table of Contents
Copyright © Roger Stokes 2001. This material may be freely reproduced, provided that this copyright notice is also reproduced.
last updated 11Jan 01