<< >> Contents Help

# 7. More Verbs

Before we can write more complex programs, we need to learn some more verbs. We will group them into classes and give a few mnemonic hints.

Before we start, I should point out a convention of J: if a dyadic verb is asymmetric, you should think of x as operating on y, i. e. x is control information and y is data. We will note the exceptions to this rule—%, /:, \:, -, -., and e.—and the reasons for the exception.

Arithmetic Dyads

All these verbs have rank 0 and produce a scalar result, so if they are applied to two operands of equal shape the result will also have that shape; if applied to two operands that agree, the result has the shape of the larger operand.

x + y addition

x - y subtraction (y operates on x to match the mathematical definition)

x * y multiplication

x % y division Note that the slash has another use, so % is division. You don't have to worry about division by zero: it produces _ (infinity) or __ (negative infinity) except for 0%0, which yields 0 .

x ^ y exponentiation (x to the power y). 0^0 yields 1 .

x ^. y logarithm (base-x logarithm of y)

x | y modulus (remainder when y is divided by x . For the longest time I had trouble remembering dyad |; it seemed that the divisor should be y by analogy to dyad % . The inconsistency is that J defines x % y as 'x divided by y' to match accepted practice in mathematics; that makes dyad % anomalous in J, because we have y operating on x).

The comparison verbs have rank 0, and produce Boolean results in which 1 means true, 0 means false. They use tolerant comparison, which means that two values that are very close to equal are considered equal. This saves you the trouble of adding small amounts to mask the effects of floating-point rounding: 1 = 3 * 1 % 3 is 1, unlike 1.0 == 3.0 * 1.0 / 3.0 whose value depends on the compiler. If you need exact comparison, look under 'Comparison Tolerance' to see how to do it.

x = y equal

x ~: y not equal (if you squint the colon looks like an equal sign)

x > y greater-than

x < y less-than

x >: y greater-than or equal (if you squint the colon looks like an equal sign)

x <: y less-than or equal

Boolean Dyads

These verbs have rank 0 and are applied to Boolean arguments to produce Boolean results:

x *. y Boolean AND

x +. y Boolean OR

x = y Boolean XNOR (1 if the operands are equal)

x ~: y Boolean XOR (1 if operands differ)

Min and Max Dyads

These verbs are useful for performing tests, because they perform the operation item-by-item, replacing a C loop that does a test for each atom. They have rank 0 and produce a scalar in each cell, so the result has the shape of the larger operand.

x >. y the greater of x and y

x <. y the lesser of x and y

Arithmetic Monads

These verbs have rank 0.

>: y increment (y+1)

<: y decrement (y-1)

<. y the largest integer not greater than y (floor function)

>. y the smallest integer not less than y (ceiling function)

| y absolute value of y

* y signum of y (_1 if y is negative, 0 if y is tolerantly close to 0, 1 if y is positive)

x o. y trigonometric function. Think of dyad o. as a monad, selecting the function based on x . For example, 1 o. y is sin(y), and _3 o. y is arctan(y). The functions are: 0 sqrt(1-sqrt(y)); 1 sin(y); 2 cos(y); 3 tan(y); 4 sqrt((y*y)+1); 5 sinh(y); 6 cosh(y); 7 tanh(y); 8 sqrt(-(1+y*y)); 9 Re(y); 10 Mag(y); 11 Im(y); 12 Angle(y). (-x) o is the inverse of x o, with the exceptions _8 -sqrt(-(1+y*y)); _9 y; _10 Conj(y); _11 j. y; _12 ^j. y .

-. y 1-y

Boolean Monad

-. y (rank 0) Negate y This is simply the boolean interpretation of 1-y .

Operations on Arrays

These verbs operate on entire arrays; they have infinite right rank (so they look at the entire y), and they have left rank as appropriate for the operation performed. I am going to give a highly simplified definition of the functions of these verbs; consult the Dictionary to see all they can do.

Dyads

Selection: { # -.

x { y (From)

No, nothing was left out! { is not paired with }; it is a verb and stands by itself.

The left rank is 0; the result is item number x of y . One of the great insights of J is the realization that selection, which in most other languages requires a special syntax like C's y[x], is really just a dyadic verb like any other. Examples:

2 { 3 1 4 1 5 9

4

y has rank 1; its items have rank 0; item number 2 is 4 .

2 4 { 3 1 4 1 5 9

4 5

The left frame is 2; each atom of x selects an item of y (each an atom), and the results are made into a 2-item list.

1 { i. 3 3

3 4 5

y has rank 2; its items have rank 1; item number 1 is 3 4 5 .

2 1 { i. 3 3

6 7 8

3 4 5

The left frame is 2; each atom of x selects an item of y (each a list), and the results are made into a 2×3-item array.

0 { 5

5

You are allowed to select item 0 of a scalar. This follows from the definition that a scalar has a single item which is the scalar itself. Selecting any other item is an error.

There are many variations on the format of x, providing for multidimensional indexing where each index can be a list. You will have to wait a bit to learn them, but I will note that a negative index counts back from the end of the array:

_1 { 3 1 4 1 5 9

9

x # y (Copy)

Left rank is 1. If x is a list whose items are all 0 or 1, the result has the same rank as y, and contains just the items of y for which the corresponding item of x is 1. For example:

1 0 1 0 0 0 # 3 1 4 1 5 9

3 4

0 0 1 # i. 3 4

8 9 10 11

x -. y (Remove)

Left rank is infinite. Any items of x that match items of y are removed:

1 2 3 4 5 4 3 -. 2 4

1 3 5 3

The verb is defined with y operating on x because of the analogy with - . If x and y are sets, x -. y is the set difference.

Indexing: i. e.

x i. y (Index Of)

The left rank is infinite. x i. y looks through the items of x to find one that matches y; the result is the item number of the first match. Examples:

3 1 4 1 5 9 i. 5

4

(i. 4 3) i. 6 7 8

2

It may occur to you that for y to match an item of x, the rank of y must be the same as the rank of an item of x (call that rix, which is one less than the rank of x (namely #$x) unless x is an atom; formally, rix is (0 >. (#$x) - 1) or, more cleverly, #${.x). If y is of higher rank, each rix-cell of y is matched against items of x . Formally, x i. y is equivalent to x i."(_,rix) y . Example:

3 1 4 1 5 9 i. 1 5

1 4

(i. 3 3) i. (i. 2 3)

0 1

If an rix-cell of y matches none of the items of x, the result value for that cell is #x, i. e. one more than the largest valid item-number of x :

3 1 4 1 5 9 i. 8 4 _1

6 2 6

To be hair-splittingly accurate we must say that x i. y is equivalent to x i."(_,rix)"_ y because the rank of dyad i. is infinite. This distinction will matter eventually.

x e. y (Element Of)

The left rank is infinite. x e. y is a lightweight version of y i. x; the result is 1 if x matches an item of y, 0 if not. The verb is applied to riy-cells of x (where riy is the rank of an item of y). Formally, x e. y is the same as (#y) ~: y i. x . Dyad e. is an exception to the rule that x is control information and y is data. It was defined to be reminiscent of mathematical epsilon meaning 'element of'.

Take and Drop: {. }.

x {. y (Take)

x }. y (Drop)

The left rank is 1, but the verb handles scalars also; we will consider only the case where x is a scalar. x {. y (take) takes the first x items of y, i. e. it produces a result which consists of the first x items of y; x }. y (drop) discards the first x items of y . If x is negative, x {. y takes the last (|x) items of y, and x }. y discards the last (|x) items (remember, |x is the absolute value of x). The rank of the result is always the same as the rank of y, and in all cases the order of items is unchanged. Examples:

2 {. 3 1 4 1 5 9

3 1

2 }. 3 1 4 1 5 9

4 1 5 9

_2 {. 3 1 4 1 5 9

5 9

_1 }. i. 3 3

0 1 2

3 4 5

x {. y always gives you as many items as you asked for. If you overtake by asking for more than #y items, J will create extra ones, filling them with 0 or ' ' as appropriate:

5 {. 3 1 4

3 1 4 0 0

_5 {. 'abc'

abc NB. Negative overtake: fills added at front

We have met fills before; they were added to bring the results from different cells of a verb up to a common shape so that they could be made into an array. The fills added by overtake are different: they are part of the execution of the verb itself. We will distinguish the two types of fill, calling the ones added by the verb itself verb fills and the ones added to make cell-results compatible framing fills. Framing fills are always 0 or ' ', but you can specify the value to use for a verb fill, using the fit conjunction !. :

5 {.!.9 (3 1 4)

3 1 4 9 9

_5 {.!.'x' 'abc'

xxabc

The fit conjunction creates a new verb; in this case {.!.f is a verb that looks just like {. but uses f for the verb fill.

The fit conjunction is by no means reserved for specifying verb fills: it is available for use on any primitive to make a small change to the operation of the primitive. If !. has a meaning for a primitive, that meaning is given in the Dictionary entry for the primitive.

Joining Arrays: ,. ,:

x ,. y (Stitch)

The left rank is infinite. x ,. y is equivalent to x ,"_1 y . That means that dyad , is applied to the corresponding items of x and y, making each item of the overall result the concatenation of the corresponding items. Example:

3 4 5 ,. 7 8 9

3 7

4 8

5 9

x ,: y (Laminate)

The left rank is infinite. x ,: y is a list of 2 items: item 0 is x and item 1 is y . If x and y do not have the same shape, they are brought to a common rank and padded with fills to a common shape. Dyad ,: concatenates x and y along an added axis, in contrast to dyad , which concatenates them along their leading axis:

3 4 5 ,: 7 8 9

3 4 5

7 8 9

Contrast this with dyad ,. above or dyad , which would produce 3 4 5 7 8 9 .

1 2 , 3 4 ,: 5 6

1 2

3 4

5 6

Take a moment to understand why in this example the first verb is dyad , and the second is dyad ,: .

Rotate Left and Shift Left: |.

x |. y (Rotate Left)

The left rank is 1, but we will discuss only the case where x is a scalar. The result has the same shape as y, with the items of y rotated x places to the left (with wraparound). If x is negative, the items are rotated to the right. Examples:

2 |. 3 1 4 1 5 9

4 1 5 9 3 1

_1 |. i. 3 3

6 7 8

0 1 2

3 4 5

x |.!.f y (Shift Left)

When the fit conjunction is used, any item that is rotated across the beginning of y is replaced by the fill f . This turns the rotate into a shift where f gives the value to be shifted in:

2 |.!.'x' 'abcde'

cdexx

_2 |.!.'x' 'abcde'

xxabc

Sort: /: \:

x /: y (Sort Up Using)

x \: y (Sort Down Using)

The left rank is infinite. x and y must have the same number of items. The items of x are records and the items of y are keys; x /: y is the records x sorted into ascending order of corresponding keys y . x \: y sorts into descending order. Examples:

3 1 4 1 5 9 /: 0 1 2 3 4 5

3 1 4 1 5 9

y was already in order.

3 1 4 1 5 9 /: 5 4 3 2 1 0

9 5 1 4 1 3

Sorting into reverse order.

3 1 4 1 5 9 /: 0 10 1 20 2 30

3 4 5 1 1 9

x in order of ascending y .

(i. 4 3) /: 10 20 1 2

6 7 8

9 10 11

0 1 2

3 4 5

Items of x in order of ascending y .

1 3 5 /: 7 8 , 1 2 ,: 4 5

3 5 1

The keys y do not have to be single numbers; they don't even have to be numeric. Here, 1 2 is lowest, then 4 5, then 7 8 . The Dictionary gives complete rules for ordering y .

Because sorting is not so easy in C, C programmers are not quick to recognize applications of /: and \: . The J implementation of /: and \: runs in linear time for most y and should not be avoided.

According to our general principle, we would expect that in dyad /: x held the keys and y the data. Dyad /: is an exception to the rule.

y /: y

y \: y

When x and y are the same, you have the simple case of sorting y into ascending or descending order.

Match: -:

x -: y (Match)

The left rank is infinite. The result is 1 if x and y are the same, 0 otherwise, except: (1) if they are numeric, the comparison is tolerant; (2) for some reason I don't understand, if they are empty, they are considered to match even if the types are different, which means that getting a result of 1 from x -: y is no guarantee that x and y will behave identically:

(0$0) -: ''

1

(1 {. 0$0) -: (1 {. '')

0

The important difference between dyad -: and dyad = is that dyad -: has infinite rank so you get a single result covering the entire array, and it won't fail if the shapes of x and y do not agree.

Monads

Enfile: ,

, y (Enfile)

, y consists of all the atoms of y, made into a list. The order is row-major order , i. e. all the atoms of item 0 of the original y come first, followed by atoms of item 1, and so on; within each item the ordering similarly preserves the order of subitems. Examples:

, i. 2 3

0 1 2 3 4 5

The atoms were made into a list.

a =. 2 2 3 $ 'abcdefghijkl'

a

abc

def

ghi

jkl

,a

abcdefghijkl

y of any shape produces a list.

Recall that a single quoted character is an atom rather than a list:

$'x'

To get a 1-character list, use monad , :

$,'x'

1

The official name for monad , is the quaint but unedifying 'ravel', meaning 'separate or undo the texture of'. I prefer the equally quaint but more descriptive 'enfile', which means 'arrange in a line (as if on a string)'.

Reverse and Transpose: |. |:

|. y (Reverse)

The items of y are put into reverse order:

|. i. 5

4 3 2 1 0

|: y (Transpose)

The axes of y are reversed. This is difficult to visualize for high ranks but easy for the most common case, rank 2:

|: i. 3 4

0 4 8

1 5 9

2 6 10

3 7 11

Take and Drop Single Item: {. {: }. }:

{. y (Head)

{: y (Tail)

}. y (Behead)

}: y (Curtail)

The operations performed are simple; the biggest problem is remembering which primitive does what. Remember that { means take and } means drop, and that . means beginning and : means end. So, {.y is the first item of y, {:y is the last item of y, }.y is all of y except the first item, }:y is all of y except the last item:

{. 3 4 5

3

{: i. 3 4

8 9 10 11

}. 3 4 5

4 5

}.y is identical to 1}.y and }:y is identical to _1}.y . {.y is not identical to 1{.y, because 1{.y has the same rank as y while {.y has the rank of an item of y .

Grade (Create Ordering Permutation): /: \:

/: y (Grade Up)

\: y (Grade Down)

/: y creates a numeric list with #y items, such that i{/:y is the index of the ith-largest item of y . (/:y){y gives y sorted into ascending order. /:y is a permutation vector, i. e. it contains each integer in the range 0 to (#y)-1. \: is similar but works in descending order. Example:

/: 3 1 4 1 5 9

1 3 0 2 4 5

Read this result as follows: the smallest item of y is item 1 (with value 1), the next-smallest is item 3 (1), then item 0 (3), then item 2 (4), then item 4 (5), then item 5 (9). Monad /: defined this way turns out to be surprisingly useful. As a limbering-up exercise in the use of permutation vectors, and an example of how compactly J can express ideas, see if you can describe in words what two applications of monad /: will give:

/: /: 3 1 4 1 5 9

2 0 3 1 4 5

Add An Axis: ,: (Itemize)

,: y

The result of ,: y has rank one higher than the rank of y, with one item, which is y . The shape of ,: y is the shape of y with 1 prepended (in plain J, $,:y is 1,$y).

Constant Verb

m"n

We have met the rank conjunction " applied to verb left arguments; applied to noun left arguments it produces a verb whose result is always the value of the noun. The created verb (which can be used as either a monad or a dyad) has ranks, given as the right operand of " . Examples:

5"_ i. 4 4

5

The simplest and most common case. Since the verb has infinite rank, it operates on the entire operand and produces the scalar value.

5"0 i. 3

5 5 5

Here the verb is applied to each 0-cell of the list, giving the scalar result for each cell.

1 2 3"0 i. 3

1 2 3

1 2 3

1 2 3

Here the result at each cell is the left argument of " , the list 1 2 3 . If you were expecting the 3 to be repeated, remember that you can look at the words as J sees them:

;: '1 2 3"0 i. 3'

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

|1 2 3|"|0|i.|3|

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

1 2 3 is a single word.

_9:…_1: 0: 1:…9: _: __:

For a few special values, namely the integers _9 through 9, infinity _, and negative infinity __, you can create an infinite-rank verb to produce the value by following the constant value with : . This is equivalent to value"_ .

3: 'abc'

3

The operand 'abc' was ignored, and the result was 3 .

<< >> Contents Help