
Alvord L.Easy J.2002
.pdfNotice that the parameter 2 is used as a right argument twice in the above expression. To permit this reuse J has two verbs left and right written as [ and ] respectively which extract the right and left arguments. Using these, the operations embedded in the above line are brought together in the form of a fork :
round=.rnd@up down ] 3.757 4.232 round 2
3.76 4.23
Explicit programming
When you start to write programs which are appreciably larger than those of the preceding subsection, joining verbs correctly can begin to make demands on mental ingenuity. Accordingly, a more conventional style of defining programs is allowed which allows left and right argument data to be referred explicitly as x. and y. respectively. Redefining ssq in this style should make things clear :
ssq=.monad define +/ *: mdev y.
)
ssq i.5
10
ssq c 21.8
Notice that mdev is still defined tacitly showing that the programmer is free to mix explicit and tacit styles in whatever way he or she find most comfortable. In the case of round we have a dyadic verb :
round=.dyad define (rnd x. up y.)down y.
)
3.757 4.232 round 2
3.76 4.23
In this case explicit programming avoids the need to use the conjunction @ which was necessary in the earlier tacit definition. If you find conjunctions are tricky to master, then the ability to switch between explicit and tacit styles can be invaluable. J even provides the capability to “translate” an explicit verb automatically into a tacit one as in the following dialogue :
9!:3(5) NB. set system for linear display of verbs
13 : '(rnd x. up y.)down y.' ([: rnd up) down ]
9!:3 is a foreign conjunction like 9!:11 which was used earlier to set the print precision. The available parameters are 2, 4 and 5, which instructs the system to set verb display to boxed, tree and linear formats respectively.
20
13 : is a code which requests the translation of whatever explicit definition string follows in quotes. The result includes a new symbol cap [: which is necessary because the translator resolves everything in terms of forks.. When a monadic function like rnd is encountered, a dummy symbol is necessary to fill the place of the left tine of the fork.
Verbs for sorting
J contains two primitive verbs for sorting, namely grade up /: and grade down \:. These return the permutations which would cause the list given as right argument to be sorted in ascending (descending) order :
4 |
3 |
/:c |
0 |
2 |
|
NB. upward sorting permutation |
|
4 |
1 |
1 2{c |
|
||||
|
|
3 |
0 |
|
NB. c sorted upwards |
||
_2 0.5 3 1 4 |
|||||||
2 |
0 |
\:c |
3 |
4 |
|
NB. downward sorting permutation |
|
2 |
1 |
3 4{c |
|
||||
4 |
3 |
0 |
1 |
|
NB. c sorted downwards |
||
|
1 0.5 |
_2 |
Each of these pairs of steps can be reduced to a hook. But first observe that the arguments of any dyadic verb can be switched from left to right by applying an adverb reflex, so that the immediately preceding result could also have been achieved using the verb {~ :
c{~2 0 1 3 4
4 3 1 0.5 _2 NB. c sorted downwards
Recall that a hook is a composite verb defined by writing two verbs one after the other so that (u v)y is equivalent to y u v(y). Thus combining the verbs {~ and /: gives
({~/:)c
_2 0.5 1 3 4 NB. c sorted upwards
leading to user-defined verbs
sortu=.{~/: NB. sort upwards sortu c
_2 0.5 1 3 4
and
sortd=.{~\: NB. sort downwards sortd c
4 3 1 0.5 _2
21
A further primitive verb nub removes duplicates from a list :
~. 4 6 2 4 4 6 2 5 4 4 6 2 5
so that an upwardly sorted list with duplicates removed is given by sortu atop nub. As you have already seen atop is expressed by the conjunction @
(sortu@~.)4 6 2 4 4 6 2 5 4 2 4 5 6
This can be made into another user defined verb :
unub=.sortu @ ~. NB. upwardly sorted nub unub 4 6 2 4 4 6 2 5 4
2 4 5 6
A verb for reversing and shifting
The verb |. in its monadic reverses a list, and in its dyadic form performs a shift, to the left if the left argument is positive, and to the right if it is negative :
|
|
|.c |
4 1 |
3 |
NB. reverse c |
|
_2 0.5 |
|
|||||
|
|
|.'J |
is |
useful.' |
|
|
.lufesu |
si |
J |
NB. shift >:i.5 two places to left |
|||
3 |
4 |
2|.1 |
2 |
3 4 5 |
||
5 |
1 |
2 |
3 4 5 |
NB. shift >:i.5 one place to right |
||
5 |
1 |
_1|.1 2 |
||||
2 |
3 |
4 |
|
|
The principle remains the same even if the argument is a list of lists :
]m=.3 5$'rosessmellsweet' NB. list of three words roses
smell sweet
1 |.m NB. shift words one place up smell
sweet roses
Suppose that a verb is wanted which removes duplicate blanks from sentences. A first step is to compare the sentence as a character list with itself shifted one place right, and marking where matching items are not equal :
test=.~:~1&|.
test s=.'how are you today ?'
1 1 1 0 0 0 1 1 1 1 0 0 0 1 1 1 1 0 0 1 1 1 1 1 1 0 1 1
22
Then use copy to retain only the marked items :
(#~test) s
how are you today ?
A flaw in the above verb is that it will remove duplicates of any character, not just space. This can be adjusted for by making a fork whose centre verb is or +. and which does a not equal ~: comparison with space :
s1=.'marry me, harry !' (#~test+.~:&' ') s1
marry me, harry !
so the final defined verb for RemoveDuplicateBlanks is rdb=.#~test+.~:&' '.
Conditional structures in J are catered for using a mechanism called a gerund, in which a succession of verbs are separated by the conjunction tie `, followed by another conjunction called agenda @., followed by a verb whose result is an integer index into the tied verb list. The overall structure is what is known in programming as a case statement. As a simple example applied to an if-then-else situation, consider how the median of a list of ordered numbers might be programmed. If the tally of the argument list is odd, then the median is the value of the middle number. If it is even the median is the mean of the values of the two middle numbers.
A first step is to obtain the index of the median value or values. Define
half=.-:@<: |
NB. halve one less than rt. argument |
If the argument is odd, the result is a single integer. However, if the argument is even the result is a fraction n.5 and what is wanted is both the floor and ceiling . The condition “is-odd” is the result of 2&| whose result must be 0 or 1 which are appropriate indices for the two case verbs and leads to the following definition :
medind=.((<.,>.)@half) ` half @.(2&|) medind # 1 3 4 7
1 2
Next apply the index(es) using from and finally use mean defined above :
(mean@:{~medind@#) 1 3 4 7
3.5
As a final step the verb sortu can be incorporated, so that the requirement that the list be ordered initially can be removed :
median=.(mean@:{~medind@#)@sortu median 7 4 1 3
3.5
23

SECTION 4 : FITTING EQUATIONS TO DATA
One of the most powerful mathematical J primitive verbs is matrix inverse, which also provides least squares fitting in its dyadic form. As an example, consider the simultaneous equations
x + 2y –3z = 15 x + y + z = 12 2x – y – z = 0
The coefficient matrix of the left hand side is :
1 |
+m=.3 3$1 2 _3 1 1 1 2 _1 _1 |
|
2 |
_3 |
|
1 |
1 |
1 |
2 |
_1 |
_1 |
Its inverse is
%.m
0 0.3333 0.3333
0.2 0.3333 _0.2667 _0.2 0.3333 _0.06667
The solution of the equations is :
15 12 0%.m
4 7 1
The functionality of %.does not stop here. Suppose
2.1 |
x,:y |
3.6 |
3.7 |
4.3 |
NB. x and |
y as laminated lists |
|||||
2.4 |
5.1 |
5.5 |
5.8 |
5.9 |
6.6 |
7.4 |
8.2 |
||||
4.1 |
6.0 |
5.5 |
8.2 |
7.5 |
12.6 |
8.1 |
10.8 |
7.2 |
13.1 |
11.3 |
15.6 |
are readings from an experiment in which a best-fitting straight line is to be found :
y%.x
1.786
says that y = 1.786x is the “best-fitting” line (in the least squares sense) of the form y = kx. It is usually more useful to fit a constant as well, that is either y = kx + c or x = ky +c. A variant of append called append items adds 1 to every item in a list :
y%.1,.x 1.272 1.563 x%.1,.y
0.8117 0.4624
so y = 1.272 + 1.563x and x = 0.812 + 0.462y are the two regression lines.
24
The right argument of %.in the first of these two phrases is equivalent to x^/i.2 since x^0 is 1 for all values of x . Thus :
y %. |
x^/i.2 |
NB. Best fitting straight line |
1.27181 |
1.56334 |
|
This idea can be immediately extended by using powers 0,1,2 in order to give the best-fitting quadratic :
y %. x^/i.3 |
NB. Best fitting quadratic |
||
2.768 |
0.8803 |
0.06781 |
|
Now suppose data are the values of a polynomial, say the cubic function 0.5x 3 + 4x2 + 5x – 6. First assign a list of the coefficients in reverse order :
coef=._6 5 4 0.5
Next supply a set of x values for which you wish to evaluate the polynomial :
+x=._4+i.9
_5 _4 _3 _2 _1 0 1 2 3
Now use a verb p.which evaluates the polynomial at all values of x.:
+y=.coef p. x
38 15 0 _7 _6 3 20 45 78
An x,y table for the polynomial is :
x,:y
_4 _3 _2 _1 0 1 2 3 4 6 1.5 _4 _7.5 _6 3.5 24 58.5 110
The best fitting straight line and quadratic are
y %. x^/i.2 20.667 10.9
y %. x^/i.3 _6 10.9 4
that is y = 10.9x + 20.667 and y = 4x2 + 10.9x – 6, whereas the best fitting cubic recovers the original coefficient values :
y %. x^/i.4 _6 5 4 0.5
25
SECTION 5 : BOXES AND RECORDS
The concept of a “box” greatly enhances the variety of data structures that J can handle. The principle is that any list structure, however complex, can be cast into a container called a box, which it itself a scalar. The analogy with records in conventional data processing should be clear, as should the application of the verb box < in the following example :
fname=.'Harry'
sname=.'Potter'
fpubl=.1998
|
shelfcode=.'childrens' |
|
||
+ |
(<fname),(<sname),(<fpubl),<shelfcode |
|||
-----+------ |
+---- |
+--------- |
+ |
|
|Harry|Potter|1998|childrens| |
||||
+----- |
+------ |
+---- |
+--------- |
+ |
Without boxing it is not possible to mix character and numeric data :
fname,sname,fpubl |domain error
| fname,sname ,fpubl
Also, boxes are complex scalar objects which are quite different both in character and in permissible operations from their contents. For example, if m=.i.3 4 :
+ |
(<m),<m |
|
|
+ |
||
1 |
2 |
+--------- |
1 |
2 |
||
|0 |
3|0 |
3| |
||||
|4 |
5 |
6 |
7|4 |
5 |
6 |
7| |
|8 |
9 |
10 |
11|8 |
9 |
10 |
11| |
+--------- |
|
|
+--------- |
|
|
+ |
The result is a list of two items in a row, each of which is a container for three lists each of four items. Adding the contents of the boxed lists works fine :
m+m
0 2 4 6
8 10 12 14
16 18 20 22
but if you try adding the containers there is a problem :
(<m)+<m |domain error
| (<m) +<m
26
This error message says clearly that adding in the numerical sense is not appropriate for the container domain, and in the same way you may not mix the numeric and character domains :
fname + fpubl |domain error
| fname +fpubl
An alternative to boxing items individually to construct a boxed list is to use the verb
link |
; : |
|
|
|
+ |
fname;sname;fpubl;shelfcode |
|||
+------ |
+---- |
+--------- |
+ |
|Harry|Potter|1998|childrens| +-----+------+----+---------+
A matching verb open undoes boxed structures, but naturally requires type consistency for the unboxed contents :
>fname;sname;shelfcode Harry
Potter childrens
that is, the result of the above open is three character lists.
A commercial type data set could be built up with further levels of boxing, for example :
rec1=.fname;sname;fpubl;shelfcode
rec2=.'Jane';'Eyre';1847;'classics'
+ |
(<rec1),:<rec2 |
|
+ |
||
+ |
|
+ |
+ |
||
|+----- |
|
+| |
|||
||Harry|Potter|1998|childrens|| |
|||||
|+----- |
+------ |
|
+ ---- |
+--------- |
+| |
+----------------------------- |
+ |
+ |
+ |
+ |
+ |
|+---- |
| |
||||
||Jane|Eyre|1847|classics| |
| |
||||
|+---- |
+---- |
+---- |
+-------- |
+ |
| |
+----------------------------- |
|
|
|
|
+ |
using laminate |
,: to align the records vertically. (n.b.(<rec1),<rec2 would be |
a list of two single items, and so, as with say 2 3, the items would be displayed side by side.) Subsequent additions to the data set are made with simple appends :
rec3=.'Peter';'Rabbit';1904;'childrens'
ds=.(rec1,:rec2),rec3
27
+ |
ds |
+ |
+ |
+ |
-----+------ |
|Harry|Potter|1998|childrens|
+----- |
+------ |
+---- |
+--------- |
+ |
|Jane |
|Eyre |
|1847|classics |
| |
|
+----- |
+------ |
+---- |
+--------- |
+ |
|Peter|Pan |
|1904|childrens| |
|||
+----- |
+------ |
+---- |
+--------- |
+ |
This is a list of three four-item lists, and so
#(rec1,:rec2),rec3
3
$(rec1,:rec2),rec3
3 4
To extract a list of shelfcodes, use transpose and then from :
|
scs=.3{|:ds |
|
|
+ |
scs |
+ |
+ |
---------+-------- |
|childrens|classics|childrens| +---------+--------+---------+
This list can now be used to select the rows which correspond to children’s books :
+ |
(scs=<'childrens')#ds |
+ |
||
-----+------ |
+---- |
+--------- |
|Harry|Potter|1998|childrens|
+----- |
+------ |
+---- |
+--------- |
+ |
|Peter|Pan |
|1904|childrens| |
|||
+----- |
+------ |
+---- |
+--------- |
+ |
To sort the records in alphabetical order of surnames use 1 to extract the snames fields, then grade-up (introduced in section 3) to find the required permutation :
/:1{|:ds 1 0 2
Then apply this to make the required selection from the list of records :
(/:1{|:ds){ds |
+ |
+ |
||
+----- |
+------ |
+---- |
||
|Jane |
|Eyre |
|1847|classics |
| |
|
+----- |
+------ |
+---- |
+--------- |
+ |
|Peter|Pan |
|1904|childrens| |
|||
+----- |
+------ |
+---- |
+--------- |
+ |
|Harry|Potter|1998|childrens| +-----+------+----+---------+
28
SECTION 6 : INVESTIGATING POSSIBILITIES
This section begins with a problem. Suppose we have a situation with four two-way choices, for each of which something must be accepted or rejected. These could be to add (or not add) onions, cheese, sausage or mushrooms to a pizza. The aim is to make a table for the cost for each of the possible selections.
First two relevant verbs base #. and antibase #:. are introduced which allow numbers to be represented in all manner of different units. For example, converting 4 hrs. 22 mins. 54 secs. to seconds, and then 2 yds. 2 feet 9 inches to inches is achieved by :
0 60 60 #. 4 22 54 NB. base for mins., secs.,is 60 60 15774
0 3 12 #. 2 2 9 NB. base for ft., ins., is 3 12
105
To convert back to the original units use #: :
0 60 60 #:15774 NB. secs to hrs. mins. secs. 4 22 54
0 3 12 #:105 NB. inches to yds. ft. ins. 2 2 9
As another example, antibase generates the individual digits in a decimal integer :
10 10 10 #:658 NB. digits in base 10
6 5 8
When the right argument is a list, the result is a list of lists :
10 10 10 10 10#:4342 8958 4646 243 10 12334 0 4 3 4 2 0 8 9 5 8 0 4 6 4 6 0 0 2 4 3 0 0 0 1 0 1 2 3 3 4
With no left argument the default number base is 2, which delivers binary numbers :
0 |
0 |
#:i.8 |
NB. 8=*/2 2 2, so it is also #:i.*/2 2 2 |
0 |
|
||
0 |
0 |
1 |
|
0 |
1 |
0 |
|
0 |
1 |
1 |
|
1 |
0 |
0 |
|
1 |
0 |
1 |
|
1 |
1 |
0 |
|
1 |
1 |
1 |
|
29