Using a Defined Adverb to Trace Execution in Tacit Programs in J
Vector 13:3, page 136
Transcribed from the printed issue; not yet reviewed. Read it in the PDF of the issue, page 136
Introduction¶
This article presents a J adverb that’s useful in tracing through tacit programs. Unlike explicitly defined programs, there is no obvious way of seeing what happens when tacit programs execute. Small programs with only four or so primitives (e.g. mean=. +/ % #) are not too difficult to analyse. However it’s quite easy to create monsters with upwards of 20 components. While you are composing the code things are clear and it’s easy to see how the code works. Later on it’s more difficult. Consider, for example, the set of scripts which accompany the PHRASES Help file. An analysis of the 52 files gives the result that of the 1093 phrases more than 20% have ten or more syntactic components. Top of the list are these two with 34 components each.
What do they do? How can we analyse and understand them?
Tracing Program Execution¶
In explicit programs you can trace execution using a function such as SHOW=. (1!:2)&2. Put it in strategic points in the program and display intermediate results. This version of SHOW displays its right argument on the screen which is then returned unchanged (a property of 1!:2&2).
If we rewrite the tacit program mean to display the results of each of its components we have:
i.e. The 3 is the number of items, the 50 is their total, and the 16.6667 is the result.
A Very Simple Example¶
It is a surprise to see that the even simpler example of Add takes you straight to the heart of the semantics of the J language.
Why has SHOW been called four times? The reason is that dyadic + has rank zero which means each element in the argument will be treated individually. Using Add monadically we see that Add is called only once because monadic + has infinite rank.
We can find the rank of functions by using the b. adverb,
A simple program like SHOW is not quite sufficient to debug and trace an explict function. Appendix 1 shows a slightly extended form used to trace the working of the rplc program in the STRINGS.JS file.
Using an Explicitly Defined Adverb¶
SHOW is clumsy to use with tacit programs because it’s a verb. Converting it to an adverb with the @ conjuction helps, but only a bit: SHOW=. (1!:2)&2 @
Using it we would redefine mean as follows:
The main drawback with this version of SHOW is that it only shows function results and not their arguments. The way round this is use an explicitly defined adverb. The following version of SHOW displays the arguments to the verb instead of the results (or, using the commented expression, both results & arguments).
SHOW=. 1 : 0
show=.1!:2&2
(x.@show) : ((show@[) x.( show@]))
NB.(show@x.@show) : ( show@((show@[) x.( show@]))) NB. results + args
)
mean=. (+/SHOW)(%SHOW)(#SHOW)
mean 2 34 45
2 34 45 NB. the argument to #
2 34 45 NB. the argument to +/
3 NB. the right hand argument to %
81 NB. the left hand argument to %
27
Coercing the Explicit Adverb to Keep Rank¶
However, caution is needed because the adverb has a significant but easily overlooked influence on the rank of the verbs it operates on. If we redefine Add=. +SHOW then although dyadic Add gives the correct result something has changed.
It is called only once instead of three times as before. To make it work properly the rank conjuction is used to coerce Add to have the same rank as + .
The "+ has forced Add to be called as many times as elements in the argument.
Agreement and Rank¶
This simple Add function also shows how agreement works when dyadic functions are called with different-shaped arguments. For example we know that 100 200 + i.2 4 produces
because the rules for agreement are satisfied. When there is agreement then J re-structures the smaller array to have the same size as the larger.
"In the phrase p v q, the arguments of v must agree in the sense that their frames (relative to the ranks of v) must be a prefix of the other. [J-Dict]"
The SHOW adverb illustrates this better using a non-zero rank verb. In the following example Add is redefined to be rank-1 and the inter-relationship between agreement and rank can be seen in the example.
When two arrays each of shape 2×3×4 are Add’ed together the program is called 6 times.
x=.((2 3 4$i.24) Add 1000*>:i.2 3 4)
1000 2000 3000 4000
0 1 2 3
5000 6000 7000 8000
4 5 6 7
9000 10000 11000 12000
8 9 10 11
13000 14000 15000 16000
12 13 14 15
17000 18000 19000 20000
16 17 18 19
21000 22000 23000 24000
20 21 22 23
However, when we try to add a 2×3 matrix to a 2×3×4 array execution starts but cannot complete.
x=.(2 3$i.6) Add (1000*>:i.2 3 4)
1000 2000 3000 4000
0 1 2
|length error
| x=.(2 3$i.6) Add (1000*>:i.2 3 4)
Defining Add to be a string concatenation would show more clearly how agreement works because the length error is avoided; e.g. Add=. ; SHOW"1
Generalised Form of the SHOW Adverb¶
This final version of SHOW is more general. It decorates the arguments and also adds a representation of the calling verb. It displays the arguments and the results; it also handles the inverse of the verb so that it can be used with the dual &. conjunction.
SHOW=. 1 : 0
NB. utilities
show =. 1!:2&2
showm =. > @ {: @ show @ (' monadic-'&;)
showdl =. > @ {: @ show @ (' dyadic left-'&;)
showdr =. > @ {: @ show @ (' dyadic right-'&;)
showmi =. > @ {: @ show @ (' inverse monadic-'&;)
showdli =. > @ {: @ show @ (' inverse dyadic left-'&;)
showdri =. > @ {: @ show @ ('inverse dyadic right-'&;)
NB. operate on verb
G=.5!:1 <'x.' NB. gerund representation of verb
AA=.G&,@< NB. the verb AA decorates the output
monadic =. show@x.@showm @( AA f.)
dyadic =. show@((showdl@(AA f.)@[) x. (showdr@(AA f.)@]))
verb=.monadic : dyadic f.
NB. operate on the inverse
INV=.x.^:_1 NB. The inverse verb
G=.5!:1 <'INV'
BB=.G&,@<
monadic=.INV@showmi @( BB f.)
dyadic=.show@( ( showdli@(BB f.)@[ ) INV ( showdri@(BB f.)@] ) )
inverse=. monadic : dyadic f.
z=.((verb"x.) :. (inverse"INV)) f.
)
Example:
fac=. (1:`(]* ($:SHOW)@<:))@. (1:<])
fac 7
monadic- $: 6
monadic- $: 5
monadic- $: 4
monadic- $: 3
monadic- $: 2
monadic- $: 1
1
2
6
24
120
720
5040
Appendix:¶
This is an example of how to use a simple SHOW function to trace execution in an explicitly defined program. It is taken from the distributed STRINGS.JS script file. The rplc program has been altered to trace execution:
rplc=: 4 : 0
NB. replace characters in text string
NB. syntax: text rplc old;new
SHOW=. 3 :(> '1!:2&2 y.' ; ' :' ; ' 1!:2&2 x.;y.' ; 'y.')
'on'=. ,&.>y.
l=. #o
c=. o E. x=. ,x.
if. (0<l) *: 1 e. c do. ('string not found or empty'SHOW x) return. end.
bx=. #i.@#
('c= '&SHOW )c=. bx c
while.('Result of while test='& SHOW) 0 e. d=. 1,<:/\(#o)<:(}.-}:) c
do. ('c becomes= '&SHOW) c=. ('Value of d='& SHOW) d#c end.
('p=. (i.#x) e. 0,c NB. p= '& SHOW) p=. (i.#x) e. 0,c
('x=. p <;.1 x NB.x= ' &SHOW )x=. p <;.1 x
('b=. o&-:@(1&$) &> x NB. b= '& SHOW) b=. o&-:@(1&$) &> x
f=. n&,@(1&}.) &.>
SHOW 'evaluation of components in the expression',(10{a.),';(f b#x) (bx b) }x'
;(('(f b#x) '&SHOW) f b#x) (('(bx b) '&SHOW) bx b) }x
)
Here is the result:
'ababababab' rplc'aba';'=ABCDEF='
┌───┬───────┐
│c= │0 2 4 6│
└───┴───────┘
┌─────────────────────┬─┐
│Result of while test=│1│
└─────────────────────┴─┘
┌───────────┬─────┐
│Value of d=│0 4 6│
└───────────┴─────┘
┌───────────┬─────┐
│c becomes= │0 4 6│
└───────────┴─────┘
┌─────────────────────┬─┐
│Result of while test=│1│
└─────────────────────┴─┘
┌───────────┬───┐
│Value of d=│0 4│
└───────────┴───┘
┌───────────┬───┐
│c becomes= │0 4│
└───────────┴───┘
┌─────────────────────┬─┐
│Result of while test=│0│
└─────────────────────┴─┘
┌─────────────────────────┬───────────────────┐
│p=. (i.#x) e. 0,c NB. p= │1 0 0 0 1 0 0 0 0 0│
└─────────────────────────┴───────────────────┘
┌────────────────────┬────┬──────┐
│x=. p <;.1 x NB.x= │abab│ababab│
└────────────────────┴────┴──────┘
┌───────────────────────────┬───┐
│b=. o&-:@(1&$) &> x NB. b= │1 1│
└───────────────────────────┴───┘
evaluation of components in the expression
;(f b#x) (bx b) }x
┌──────────┬───┐
│(bx b) │0 1│
└──────────┴───┘
┌──────────┬─────────┬───────────┐
│(f b#x) │=ABCDEF=b│=ABCDEF=bab│
└──────────┴─────────┴───────────┘
=ABCDEF=b=ABCDEF=bab