<<     >>     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 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 .  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 : 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 .  As dyads, they pick one operand: x [ y is x, and x ] y is .  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 v@:[ y applies v to x, and x v@:] y applies v to .  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