>>  <<  Usr  Pri  JfC  LJ  Phr  Dic  Voc  !:  Help  Learning J

Chapter 12: Explicit Verbs

This chapter continues from Chapter 04 the theme of the explicit definition of verbs.

12.1    The Explicit Definition Conjunction

Recall from Chapter 04 the example of an explicit dyadic verb, the "positive difference" of two numbers, defined as larger minus smaller.
   PosDiff =: 4 : '(x >. y) - (x <. y)'
   
   3 PosDiff 4
1
The general scheme for the explicit definition of a function is to provide two arguments to the Explicit Definition conjunction ( : ,   colon) in the form
             type : body
In the body, the variables x and y are the arguments.

12.1.1 Type

The type is a number: type-3 functions are monadic verbs or ambivalent verbs. Type-4 functions are strictly dyadic verbs (that is, with no monadic case). There are other types: types 1 and 2 are operators, covered in Chapter 13 . Type 13 is covered in Chapter 10 .

12.1.2 Mnemonics for Types

The standard J profile predefines several variables to provide mnemonic names for the types, and other things, thus:
   noun        =: 0
   adverb      =: 1
   conjunction =: 2
   verb        =: 3
   monad       =: 3
   dyad        =: 4
   def         =: :
   define      =: : 0
Thus the PosDiff example above could be also written as:
   PosDiff =: dyad def '(x >. y) - (x <. y)'
   
   3 PosDiff 4
1
   

12.1.3 Body Styles

The body of an explicit definition consists of one or more lines of text. There are several ways to provide the body The example above, PosDiff, shows a single line written as a string.

A multi-line body can be introduced with a right argument of 0 for the colon operator.

   PosDiff =: 4 : 0
larger  =. x >. y
smaller =. x <. y
larger - smaller
)
   
   3 PosDiff 4
1
Another variation allows a multi-line body to be written compactly by embedding line-feeds. LF is predefined to be the line-feed character. Notice that the whole body must be parenthesized.
   PosDiff =: 4 : ('la =. x >. y', LF, 'sm =. x <. y', LF, 'la - sm')
   

PosDiff 3 PosDiff 4
+-+-+------------+
|4|:|la =. x >. y|
| | |sm =. x <. y|
| | |la - sm     |
+-+-+------------+
1

Another variation uses a boxed list of lines (again with the body parenthesized):

   PosDiff =: 4 : ('la =. x >. y' ; 'sm =. x <. y' ;  'la - sm')

PosDiff 3 PosDiff 4
+-+-+------------+
|4|:|la =. x >. y|
| | |sm =. x <. y|
| | |la - sm     |
+-+-+------------+
1

Notice that these are not variations of syntax, but rather alternative expressions for constructing a data-structure acceptable as the right-argument of the : operator.

12.1.4 Ambivalent Verbs

An ambivalent verb has both a monadic and a dyadic case. In the definition, the monadic case is presented first, then a line consisting of a solo colon, and then the dyadic case. For example:
   log =: 3 : 0
^. y     NB. monad - natural logarithm 
:
x ^. y   NB. dyad  - base-x  logarithm  
)
   

log 2.7182818 10 log 100
1 2

12.2 Assignments

In this section we consider assignments, which are of significance in defining explicit functions.

12.2.1 Local and Global Variables

Consider the example
   foo =: 3 : 0
L =.  y
G =:  y
L
)
Here, the assignment of the form
               L =. expression
causes the value of expression to be assigned to a local variable named L. Saying that L is local means that L exists only while the function foo is executing, and furthermore this L is distinct from any other variable named L. By contrast, the assignment of the form
               G =: expression
causes the value of expression to be assigned to a global variable named G. Saying that G is global means that the unique variable G exists independently, in its own right.

To illustrate, we define two GLOBAL variables called L and G, then execute foo to show that the L mentioned in foo is not the same as global L, while the G mentioned in foo is the same as global G:

   L =: 'old L'
   G =: 'old G'
   

foo foo 'new' L G
+-+-+-------+
|3|:|L =.  y|
| | |G =:  y|
| | |L      |
+-+-+-------+
new old L new

With versions of J from J6 onward, it is regarded as an error to make a global assignment (with =:) to a variable with the same name as an already-existing local variable.

For example, the argument variables x and y are local, so it would normally be an error in an explicit verb to make a global assignment to a variable named y .

   foo =: 3 : 0
z =. y + 1
y =: 'hello'
z
)
   
   foo 6 
|domain error: foo
|   y    =:'hello'
   
If we really, really wanted to assign to a global named y from within an explicit definition, the local y must first be erased.
   foo =: 3 : 0
z =. y+1
erase <'y'
y =: 'hello'
z
)
   
   foo 6
7
   y
hello
   
   

12.2.2 Local Functions

We have seen local variables, which are nouns. We may also have local functions. A local function may be tacit or explicit, as in the following example
   foo =: 3 : 0
Square  =. *:
Cube    =. 3 : 'y * y * y'
(Square y) + (Cube y)
)
   
   foo 2
12
However, what we can't have is an explicit local function defined by an inner multiline body Recall that a multiline body is a script terminated by a solo right parenthesis, so we cannot have one such body inside another. Instead, we could use an alternative form for the body of an inner function, such as scale in the following example:
   FTOC =: 3 : 0
   line1   =. 'k =. 5 % 9'
   line2   =. 'k * y'
scale =. 3 : (line1 ; line2)  
scale y - 32
)
   
   FTOC 212
100
One final point on the topic of inner functions. A name, of a variable or function, is either global or local. If it is local, then that means it is recognised in the function in which it is defined. However it is not recognised in any inner function. For example:
   K =: 'hello '
   
   zip =: 3 : 0
K =. 'goodbye '
zap =. 3 : 'K , y'
zap y
)
   
   zip 'George'
hello George
We see that there is a global K and a local K. The inner function zap uses the global K because the K which is local to zip is not local to zap.

12.2.3 Multiple and Indirect Assignments

J provides a convenient means of unpacking a list by assigning different names to different items.

'day mo yr' =: 16 10 95 day mo yr
16 10 95 16 10 95

Instead of a simple name to the left of the assignment, we have a string with names separated by spaces.

A variation uses a boxed set of names:

('day';'mo';'yr') =: 17 11 96 day mo yr
17 11 96 17 11 96

The parentheses around the left hand of the assignment force evaluation as a set of names, to give what is called "indirect assignment". To illustrate:

   N =: 'DAY';'MO';'YR'

(N) =: 18 12 97 DAY MO YR
18 12 97 18 12 97

As a convenience, a multiple assignment will automatically remove one layer of boxing from the right-hand side:

(N) =: 19;'Jan';98 DAY MO YR
+--+---+--+
|19|Jan|98|
+--+---+--+
19 Jan 98

12.2.4 Unpacking the Arguments

Every J function takes exactly one or exactly two arguments - not zero and not more than two. This may appear to be a limitation but in fact is not. A collection of values can be packaged up into a list, or boxed list, to form in effect multiple arguments to the J function. However, the J function must unpack the values again. A convenient way to do this is with the multiple assignment. For example, the familiar formula to find the roots of a quadratic (a*x^2) +(b*x)+c, given the vector of coefficients a,b,c might be:
   rq =: 3 : 0
'a b c' =. y
((-b) (+,-) %: (b^2)-4*a*c) % (2*a)
)

rq 1 1 _6 rq 1 ; 1 ; _6
2 _3 2 _3

12.3 Control Structures

12.3.1 Review

Recall from Chapter 04 the positive-difference function defined as:
   POSDIFF =: 4 : 0
if.   x > y
do.   x - y
else. y - x
end.
)
   
   3 POSDIFF 4
1
Everything from if. to end. is called a "control structure". In it, if. do. else. and end. are called "control words".

The plan for this section is to use this example for a general discussion of control structures, and then go on to look at a number of particular control structures.

12.3.2 Layout

We can freely choose a layout for the expressions and control words forming a control structure. Immediately before or immediately after any control word, any end-of-line is optional, so that we can choose to remove one or insert one. For example, by removing as many as possible from POSDIFF we get
   PD =: 4 : 'if.  x > y  do.  x - y  else.  y - x  end. '
   
   3 PD 4
1
   

12.3.3 Expressions versus Control Structures

We speak of evaluating an expression. We regard assignments as expressions, since they produce values, but in this case it is natural to speak of "executing" the assignment, since there is an effect as well as a value produced. We will use the words "execute" and "evaluate" more or less interchangeably.

Executing (or evaluating) a control structure produces a value, the value of one of the expressions within it. Nevertheless, a control structure is not an expression, and cannot form part of an expression. The following is a syntax error:

   foo =: 3 : '1 + if. y > 0 do. y else. 0 end.'
   
   foo 6
|syntax error: foo
|       1+
Observing the distinction between expressions and control structures, we can say that the body of an explicit definition is a sequence of items, where an item is either an expression or a control structure. Here is an example where the body is an expression followed by a control structure followed by an expression.
   PD1 =: 4 : 0
w =. x - y
if. x > y do. z =. w  else. z =. - w end.
z
)
   
   3 PD1 4
1
   
The value produced by a control structure is discarded if the control structure it is not the last item in the sequence. However, this value can be captured when the item is the last, so that the value becomes the result delivered by the function.

Hence the previous example can be simplified to:

   PD2 =: 4 : 0
w =. x - y
if. x > y do. w else. - w end.
)
   
   3 PD 4
1
   

12.3.4 Blocks

The examples above show the pattern:
                if. T do. B1 else. B2 end.
meaning: if the expression T evaluates to "true", then execute the expression B1, and otherwise execute the expression B2.

Expression T is regarded as evaluating to "true" if T evaluates to any array of which the first element is not 0.

   foo =: 3 : 'if.  y do. ''yes''  else. ''no''  end.'
   

foo 1 1 1 foo 'abc' foo 0 foo 0 1
yes yes no no

More generally, T, B1 and B2 may be what are called "blocks". A block is a sequence of items, where an item is either an expression or a control structure. The result delivered by a block is the value of the last item of the block.

Here is an example, to form the sum of a list, where the T-block and the B2-block each consist of a sequence.

   sum =: 3 : 0
if. 
    length  =. # y      NB. T block
    length  = 0         NB. T block
do. 
    0                   NB. B1 block
else. 
    first =. {. y       NB. B2 block
    rest  =. }. y       NB. B2 block
    first + sum rest    NB. B2 block
end.
)
   
   sum 1 2 3
6
Here we see that the value of the T-block (true or false) is the value of the last expression in the sequence, (length = 0)

The items of a block may be (inner) control structures. For example, here is a function to classify the temperature of porridge:

   ClaTePo =: 3 : 0
if. y > 80  do.      'too hot'
else.
      if. y < 60 do. 'too cold'
      else.          'just right'
      end.
end.
)
   
   ClaTePo 70
just right

12.3.5 Variants of if.

A neater version of the last example is:
   CLATEPO =: 3 : 0
if.     y > 80 do. 'too hot'
elseif. y < 60 do. 'too cold'
elseif. 1      do. 'just right'
end.
)
   
   CLATEPO 70
just right
   
showing the pattern:
         if. T1 do. B1 elseif. T2 do. B2  ... elseif. Tn do. Bn end.
Notice that according to this scheme, if all of the tests T1 ... Tn fail, then none of the blocks B1 .. Bn will be executed. Consequently we may wish to make Tn a catch-all test, with the constant value 1, as in the example of CLATEPO above.

If all the tests do fail, so that none of the blocks B0 ... Bn is executed, then the result will be i. 0 0 which is a J convention for a null value.

   foo =: 3 : 'if. y = 1 do. 99 elseif. y = 2 do. 77 end. '
   
   (i. 0 0) -: foo 0
1
   
There is also the pattern:
          if. T do. B end.
Here either B is executed or it is not. For example, positive-difference yet again:
   PD =: 4 : 0
z =. x - y
if. y > x do. z =. y - x end.
z
)
   
   3 PD 4
1
   

12.3.6 The select. Control Structure

Consider this example of a verb to classify a name, using an if. control structure.
   class =: 3 : 0
t =. 4 !: 0 < y
if.     t = 0 do. 'noun'
elseif. t = 1 do. 'adverb'
elseif. t = 2 do. 'conjunction'
elseif. t = 3 do. 'verb'
elseif. 1     do. 'bad name'
end.
)
   
   class 'class'
verb
   class 'oops'
bad name
   
A neater formulation is allowed by the select. control structure.
   CLASS =: 3 : 0
select.  4 !: 0 < y
case. 0 do. 'noun'
case. 1 do. 'adverb'
case. 2 do. 'conjunction'
case. 3 do. 'verb'
case.   do. 'bad name'
end.
)
   
   CLASS 'CLASS'
verb
   CLASS 'oops'
bad name
   
Suppose we are interested only in a three-way classification, into nouns, verbs and operators (meaning adverbs or conjunctions). We could of course write:
   Class =: 3 : 0
select.  4 !: 0 < y
case. 0 do. 'noun'
case. 1 do. 'operator'
case. 2 do. 'operator'
case. 3 do. 'verb'
case.   do. 'bad name'
end.
)
   
but this can be abbreviated as:
   Clss =: 3 : 0
select.  4 !: 0 < y
case. 0    do. 'noun'
case. 1;2  do. 'operator'
case. 3    do. 'verb'
case.      do. 'bad name'
end.
)
   

Clss 'Clss' o =: @: Clss 'o' Clss 'oops'
verb +--+
|@:|
+--+
operator bad name

12.3.7 The while. and whilst. Control Structures

In the general pattern
             while. T do. B end.
block B is executed repeatedly so long as block T evaluates to true. Here is an example, a version of the factorial function:
   fact =: 3 : 0
r =. 1
while. y > 1
do.    r  =. r * y
       y =. y - 1
end.
r
)
   
   fact 5
120
The variation whilst. T do. B end. means
             B
             while. T do. B end.
that is, block B is executed once, and then repeatedly so long as block T is true.

12.3.8 for.

The pattern
             for_a. A do. B. end.
means: for each item a in array A, execute block B. Here a may be any name; the variable a takes on the value of each item of A in turn. For example, to sum a list:
   Sum =: 3 : 0
r =. 0
for_term. y do.  r =. r+term end.
r
)
   
   Sum 1 2 3
6
In addition to the variable a for the value of an item, the variable a_index is available to give the index of the item. For example, this function numbers the items:
   f3 =: 3 : 0
r =. 0 2 $ 0
for_item. y do.  r =. r , (item_index; item) end.
r
)
   
   f3 'ab';'cdef';'gh'
+-+----+
|0|ab  |
+-+----+
|1|cdef|
+-+----+
|2|gh  |
+-+----+
Another variation is the pattern for. A do. B end. in which block B is executed as many times as there are items of A. For example, here is a verb to count the items of a list.
   f4 =: 3 : 0
count =. 0
for. y do. count =. count+1 end.
)
   
   f4 'hello'
5
   

12.3.9 The return. Control Word

Suppose we need to define a verb to test for a small integer scalar. "Small" means magnitude less than 100, say. This would do:
   test =: 3 : 0
    if. 4 = 3 !:0 y  do.       NB. integer ?
        if. 0 = # $ y  do.     NB. scalar ?
            100 > | y          NB. small ?
        else. 0
        end.
    else. 0
    end.
)   
   

test 17 test 'hello' test 1 2 3 test 101
1 0 0 0

Clearly we must check for an integer before testing the integer for smallness. Hence the nested ifs.

Here is a neater alternative:

   test =: 3 : 0
    if. 4 ~: 3!:0 y do. 0 return. end.    NB. not integer
    if. 0 ~: # $ y  do. 0 return. end.    NB. not scalar
    100 > | y                             NB. small ?
)

test 17 test 'hello' test 1 2 3 test 101
1 0 0 0

The effect of the return. control word is to short-circuit any further execution of the verb, delivering the most-recently computed value, which in this example will be 0 at each return. .

12.3.10 Other Control Structures

Chapter 29 covers the control structure try. catch. end. . Other control words and structures are covered in the J Dictionary

This is the end of Chapter 12.


NEXT
Table of Contents
Index


The examples in this chapter were executed using J version 802 beta. This chapter last updated 01 Nov 2014
Copyright © Roger Stokes 2014. This material may be freely reproduced, provided that acknowledgement is made.


>>  <<  Usr  Pri  JfC  LJ  Phr  Dic  Voc  !:  Help  Learning J