I've been playing with J 2.7 for PC, looking for pointers on the array
syntax to build for a mini-language of my own. I like it very much, but
it has its difficulties too, and at this point I'd like to share my
experiences...
What I wanted was to set up a family of point transformations: translations,
rotations, etc. These functions would be parametrized, as in
x = 3 4 5
v = 2 2 2
Translate(v) x = 5 6 7
Ideally,
(1) A function could be packaged with its inverse, and I could do things
like
~( Trans(u) Trans(v) ) x
and have that give the same result as
~Trans(v) ~Trans(u) x
(2) Either the x or v argument could be early or late evaluated.
(3) I could easily modify my functions for one-x-many-v, one-v-many-x,
one-v-for-each-x, and each-x-with-each-v.
To summarize, I can do each of these things, but getting them all at
once brings out some problems. And
(4) There should be some way to abstract both the operation (Trans) and
the arguments, to build a family of similar transformation functions.
seems very awkward indeed.
What we need basically is addition, modified for rank 1:
+"1
This immediately gives the first three cases of (3), and then we can
have
+"1/
for tables.
To compound transforms,
v1 +"1 v2 +"1 x
but what looks nicer is
tr =. +"1
tr&v1 tr&v2 x
or
trv1 =. +"1 & v1
trv2 =. +"1 & v2
trv1 trv2 x
(N.b. I was too greedy here, and what I wound up with was the equivalent
of
x +"1 v2 +"1 v1
which is correct for this case, but not necessarily for not-commutative
functions.)
To make these invertible,
trv =. (+"1 & v) :. (-"1 & v)
Then with x = 3 4 5, v = 2 2 2,
trv^:1 x = 5 6 7
trv^:2 x = 7 8 9
trv^:(0 1) x = 3 4 5
5 6 7
and even
trv^:_1 x = 1 2 3
Better still,
v1 =. 2 2 2
v2 =. 10 10 10
trv1 =. (+"1 & v1) :. (-"1 & v1)
trv2 =. (+"1 & v2) :. (-"1 & v2)
trv1^:_1 trv2^:_1 x = _9 _8 _7
(trv2 & trv1)^:_1 x = _9 _8 _7
I tried
tr =. (+"1) :. (-"1)
trv =. tr & v
trv^:n x gives the expected results for non-negative n, but
gets a domain error for negative. Evidently inverses can only be evoked
for verbs with :. at the top level (clearly shown in the box display of
trv).
That seems a reasonable policy, because the & conjunction has to do
service two ways:
(+"1 & v) x = x +"1 v
(v & +"1) x = v +"1 x
However, when I thought it over, I could see no contradiction in having
an inverse defined for a dyadic, and having it automatically extended
to right and left:
(-"1 & v) x = x -"1 v
(v & -"1) x = v -"1 x
So these are different values, so what? Just means you get two monadic
inverses for the price of one. Comments?
Getting late evaluation of the noun operands is not as easy as it looks.
Trying for late v, with v = 3 3 3 at define time,
(+"1 & ". 'v') evaluates early, to 3 3 3
(+"1 & (". 'v')) at least gives a verb, the equivalent of (+"1 & 3 3 3)
WHY are these different?
After a good deal of trial and error, I got it to work with a hook:
((+"1 ".) & 'v') evaluates to a boxed verb with a v in it.
I take this to indicate that, to keep the ". from executing at define-time,
you have to drag it inside a verb which will not itself be executed until
it gets (in this case) a left operand. I feel there ought to be a cleaner
way.
Our full transform verb is then:
trv =. ((+"1 ".) & 'v') :. ((-"1 ".) & 'v')
This has all the nice function-power properties. We need a similar verb
with +"1/ for tables, though.
Trying to build an expression on this basis which also evaluates x late
defeats me. I just can't keep ". from evaluating early. I gather the
point is moot, since verbs will be late-evaluated by default in Version 3.2
anyway.
All right then, there's our trv. Now suppose I want trv1 and trv2.
Do I have to type their definitions literally, or is there some way
to abstract those 'v's, and substitute 'v1', 'v2'?
Apparently not. There seem to be two approaches: (1) defining a monadic
verb with :: and some string-handling (2) doing surgery on the box form
of trv.
I'm not enamoured of these :: text definitions. I have to say that if
this is going to be the general means of function definition, then we
need something closer to a macro facility. Otherwise one gets into the
following kind of unpleasantness:
trvpattern =. '((+"1 ".) & '; ''; ') :. ((-"1 ".) & '; ''; >'))'
mtrv1 =. (> 0{ trvpattern), 'v1', (> 2{ trvpattern), 'v1',
(> 4{ trvpattern)
trv1 =. mtrv1 :: ''
And where is the legendary brevity of the APL family in this?
I could hack that, in principle, but the real problem with this approach
is that the resulting expression does not have :. holding the top-level
functions together, so we lose the inversion ability of ^:_1 again. If
we want it back, we have to build up something like
mtrv1fwd::'' :. mtrv1bwd::'' where each of the expressions
referred to is built up as above.
Approach (2); well, it looks as if it can be done, with enough opening
and closing of boxes. But I'm not certain whether the boxes we see in
these verb diagrams are the same ones we use when forming boxed expressions.
The bottom line is, J does not yet seem to have the control over its own
parts of speech that every interpretive language requires. I'm not
impatient, the care that has gone into exploiting 22 typewriter keys
is perfectly awesome. Better this thing should be done right than soon.
In my tentative opinion, the appropriate way to go is neither to push
character arrays in non-array-like directions, nor to build a calculus
of box-nests. It would be more in character to build up the repertoire
of adverbs and conjunctions: powerful abstractions for building functions
out of functions.
Also, it's plain that J really has two components, more or less modular:
one is the array processing, the other is the evaluation algorithm. The
former is hellishly powerful, a good step up from APL. The latter is
elegant, but we need a better understanding of when and how the various
parts of speech come into play.
Roger Hui has my profound admiration.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Jonathan Burns | They finally discovered that the ONE thing
Computer Science Dept | commenting decompiler ...
La Trobe University |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~