Compound Verbs

<< >> Contents Help

# 10. Compound Verbs

On New Year's Day my rich uncle gives me x dollars, which I add to the y dollars I already have earning 4% interest. How much money will I have at the end of the year? Simple in J—I just write 1.04 * x + y, and I have the answer, whether x and y are scalars or arrays. That's nice, but here's my problem: I expect his largesse to continue, and in my anticipation I have estimated his gifts for the next few years as the list x; I want to know what I'll be left with at the end. I need to pass each year's starting balance into the calculation for the next year. I know what I want the result to look like: it'll be v/ (|.x) , y which will be evaluated as xn v …x2 v x1 v x0 v y . But what is v? The problem with 1.04 * x + y is that it contains 2 verbs and a constant, and I need it all lumped into a single verb so that I can have the adverb dyad / modify the whole thing. One solution would be to create the verb

v =: dyad : '1.04 * x. + y.'

after which v/ (|.x),y works, but it's a shame to have to interrupt a J sentence just to define a verb with such a puny function—I want magic words to let me say (1.04 * + abracadabra…combine!)/ (|.x),y . J has such magic words, and we will learn a few now.

The magic words will join verbs and nouns together, so they must be modifiers: adverbs and conjunctions. Before we start, we need a little notation to help with the different cases we will encounter. Given a conjunction c or adverb a, we call its left operand m if it is a noun, or u if it is a verb. Similarly we call a conjunction's right operand n if it is noun, v if a verb. There are four possible ways to invoke a conjunction (u c v, m c v, u c n, and m c n) and two for an adverb (u a and m a) and they are defined independently. Moreover, the derived verb produced by the invocation (the derived entity may be a noun, adverb, or conjunction too but that is unusual) can be used as a dyad (e. g. x u c n y) or as a monad (e. g. m a y), and those cases are defined independently as well. You won't get the cases mixed up, because verbs and nouns are so different that it will seem natural for u c n to be different from u c v; just be aware that the variants are many and that we will be learning a tiny subset of J's toolkit. The adverb / is an example: we have learned about monad u/, but dyad u/ is very different, as is m/ .

Verb Sequences—u@:v and u@v

u@:v creates a derived verb of infinite rank that applies v to its argument(s) and then applies u to the result. In other words, u@:v y is the same as u v y and x u@:v y is the same as u x v y . Examples:

{. @: /: 3 1 4 1 5 9

1

Monad /: produced the permutation 1 3 0 2 4 5 of which we took the first item.

1 2 3 +/@:* 1 2 3

14

Dyad * produced 1 4 9 whose items we then summed. fndisplay shows the details:

defverbs 'plus"0 times"0'

1 2 3 plus/@:times 1 2 3

+-------------------------------------------+

|(1 times 1) plus (2 times 2) plus 3 times 3|

+-------------------------------------------+

u@v is like u@:v except that the rank of the derived verb is the rank of v (also expressible as (u@:v)"v because u"v is defined to have the function of u with the rank of v). My advice is to stick to @: and avoid @ unless you're sure you need it.

The Difference Between u@:v and u@v

Because u@:v and u@v have very similar definitions, and produce identical results in many cases, almost every beginning J programmer confounds the two. The key is to remember that each sequence produces a new verb which has a rank. In u@:v, this rank is infinite, so that in x u@:v y, the derived verb u@:v is applied to the entire x and y, meaning that v is applied to the entire x and y and u is applied to the entire result of v . In the other case, the rank of u@v is the rank of v, so in x u@v y the verb u@v is applied to individual cells of x and y, where the cell-size is given by the rank of v : for each of those cells, v is applied followed by u, and the results from the cells are collected into an array.

If we try to take the sum-of-products using u@v instead of u@:v, we see the difference between the two forms:

1 2 3 +/@* 1 2 3

1 4 9

What happened? We thought we were multiplying the vectors and then taking the sum. Because we used @ rather than @:, the derived verb had the rank of dyad *, namely 0, which means that the derived verb was applied to each cell: at each cell we multiplied and then took the sum of the single cell. In fndisplay form,

defverbs 'plus"0 times"0'

1 2 3 plus/@times 1 2 3

+---------+---------+---------+

|1 times 1|2 times 2|3 times 3|

+---------+---------+---------+

plus never got executed, because plus/ was applied to 1-element lists, leaving in each case the single element.

Many J programmers think of @ and @: as establishing a different kind of connection between u and v, with u@:v applying u to the entire result of v and u@v applying u to result cells of v (where a result cell is the output produced by applying v to a single operand cell). Such an interpretation makes it easy to understand the operation of +/@* : +/ is applied on result cells of *, which are scalars.

The connection interpretation of u@v correctly accounts for the results produced by J, but as you use it you should be aware that it is inaccurate because it suggests that v is executed against the operand(s) in their entirety. The actual cell-at-a-time execution of u@v is different in two ways: it is slower because the verb v must be restarted for each cell; and if the temporary space required by u or v is large, cell-at-a-time execution uses less space because the temporary space for each cell is freed before the next cell is processed.

Making a Monad Into a Dyad: The Verbs [ and ]

The characters [ and ] are not paired in J; each is an independent verb. This is jarring at first but you'll get used to it.

[ and ] are identity verbs: they have infinite rank, and ] y and [ y both result in y . As dyads, they pick one operand: x [ y is x, and x ] y is y . They can be useful when you have a monadic verb that for one reason or another must be used as a dyad with an unwanted operand: then x v@:[ y applies v to x, and x v@:] y applies v to y . Example:

1 2 3 {.@:[ 4 5 6

1

Here are some other uses of [ and ] . We have already met the first one, which is to display the result of an assignment:

a =. 1 2 3

produces no typeout, but

]a =. 1 2 3

1 2 3

Second, [ can be used to put multiple assignments on the same line, since each application of [ ignores what is to its right:

a =. 5 [ b =. 'abc' [ c =. 0

Finally, ] can be used instead of parentheses to separate numbers that would otherwise be treated as a list:

5 ,"0 1 2

|syntax error

| 5 ,"0 1 2

5 ,"0 (1 2)

5 1

5 2

5 ,"0 ] 1 2

5 1

5 2

Making a Dyad Into a Monad: u&n and m&v

A dyadic verb takes two operands, but if you know you are going to hold one fixed, you can create a monadic verb out of the combination of the dyad and the fixed operand; the monad's operand will be applied to whichever operand of the dyad was not held fixed. The conjunction &, when one of its operands is a noun, fixes an operand to a dyad: m&v y has infinite rank and is equivalent to m v y; u&n y has infinite rank and is equivalent to y u n . Examples:

2&^ 0 1 2 3

1 2 4 8

(-&2) 4 5 6

2 3 4

Now we can solve our original problem, which was to put 1.04 * x + y into the form x v y . v should be

1.04&* @: +

which we can verify using fndisplay as

defverbs 'plus"0 times"0'

defnouns 'x y'

x 1.04&times @: plus y

+-------------------+

|1.04 times x plus y|

+-------------------+

and to get my total savings after receiving all payments I use monad / to apply that verb for each payment, giving the expression:

1.04&* @: + / (|.x) , y

Let's take a moment to understand the parsing and execution of 1.04&* @: + / . The left operand of a modifier includes all preceding words up to and including the nearest noun or verb that is not immediately preceded by a conjunction. This is a precise way of saying that modifiers associate left to right. In the phrase 1.04&* @: + /, the 1.04 is not preceded by a conjunction, so it is the beginning of all the conjunctions' left operands, and the verb is parsed as if it were written (((1.04&*) @: +) / ) .

Note that left-to-right association of modifiers corresponds to right-to-left execution. When the derived verb monad (((1.04&*) @: +) / ) is executed, it performs according to the definition of monad u/, with ((1.04&*) @: +) as the u; execution of monad u/ inserts u between items, so ((1.04&*) @: +) is executed between items; at each such execution the dyad + is executed first, followed by the monad 1.04&* . Fortunately, the result of the parsing rules is that conjunctions and adverbs, just like verbs, should be read right-to-left.

If I wanted to spend half of my uncle's money , the amount I would be left with is

0.5 * 1.04&* @: + / (|.x) , y

No parentheses are needed, because 1.04 is still not preceded by a conjunction and so 1.04&* @: + / (|.x),y is still evaluated before that value is multiplied by 0.5 .

Once you get the hang of it, you will be able to understand and build composite verbs of great power. That will be a useful skill to develop, because you never know when you are going to want to make some sequence of functions the operand of a modifier, and then you're going to have to be able to express the sequence in a single compound verb. It will take a lot of practice, as well as coding techniques to break a gristly mass of conjunction-bound words into digestible pieces (we'll learn them later). For the time being, be content if you can understand the simple examples shown above.

<< >> Contents Help