J: a little exercise
Author Message J: a little exercise

Jonathan Burns:
[] 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?

It is generally true that if both
y = (x&G) (x&g) y
x = (G&y) (g&y) x
then G might be considered an 'dyadic inverse' of g.  Obviously, this
is not considered in the current versions of J.

[] Getting late evaluation of the noun operands is not as easy as it looks.

Try

For example,
'name' late
is a monadic function which always returns the current value of the
pronoun 'name'.

[] 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?

The first is equivalent to
((+"1 & ".) 'v')
since conjunctions parse left to right.

...
[] 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.

I'm not sure I understand what the semantics of [+"1/] are supposed to
be, such that you can invert it.  Inverse doesn't have a functional
meaning except with monads.

[] 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.

Again, I'm not sure what is being said here.  Note that in 3.2 nouns
are still evaluated greedily.  At a guess, though, you want something
like.

example =. 'x f y' late

which is a monadic verb which ignores its argument, but resolves the
binding of 'x', 'f', and 'y' at the time that 'example' is passed an
argument.

[] 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'?

The problem here is still that inverse doesn't understand about the
obverse of a dyadic function.  This requires either a language change
or that you define your own version of 'inverse'.  Other than that,
all you're doing is defining new names for addition.

[] 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.

Well, no, the real problem here is that the inverse operator is not
general enough.  [Though I agree about the care which has gone into
the language design.]

--

Fri, 11 Mar 1994 04:17:17 GMT  J: a little exercise
It is generally true that if both
y = (x&G) (x&g) y
x = (G&y) (g&y) x
then G might be considered an 'dyadic inverse' of g.  Obviously, this
is not considered in the current versions of J.

However, on consideration of the definition of CHAIN (f^:n, used
dyadically), I think it would be better to make the conditions:
y = (G&x) (x&g) y
x = (y&G) (g&y) x
for G to be considered a 'dyadic inverse' of g.

--

Fri, 11 Mar 1994 04:20:34 GMT  J: a little exercise
Let's see if I can complete my idea, this time...

I think it would be better to make the conditions:
y = (G&x) (x&g) y
x = (y&G) (g&y) x
for G to be considered a 'dyadic inverse' of g.

Note that if (g =. +) there is no function G which is a complete
inverse of g.  If (G =. -), then the first condition holds, but the
second condition does not.  If (G =. -~) then the second condition
holds but the first does not.  It would be a shame to be limited to an
implementation of dyadic inverse which cannot deal with (+).

So, perhaps the best thing to do would be to allow a gerundial left
argument to obverse.  The structure of this argument would be vaugely
patterned after the right argument to rank (").  So, for example, a
person might define:

minus =. - ` (-~) ` + :. -

so that, for example,
inv =. ^: _1

minus inv
+-----+--+-+
|minus|:.|-|
+-----+--+-+
minus inv minus 4
4

5&minus inv
+-----------+--+-----------+
|+-+-+-----+|:.|+-----+-+-+|
||5|&|minus||  ||+-+-+|&|5||
|+-+-+-----+|  |||-|~|| | ||
|           |  ||+-+-+| | ||
|           |  |+-----+-+-+|
+-----------+--+-----------+
5&minus inv  5&minus 4
4

minus&5 inv
+-----------+--+-------+
|+-----+-+-+|:.|+-+-+-+|
||minus|&|5||  ||5|&|+||
|+-----+-+-+|  |+-+-+-+|
+-----------+--+-------+
minus&5 inv  minus&5 ]4
4

Note that there is a little ambiguity here regarding the monadic and
dyadic case.  For example (minus inv inv & 5) may be treated rudely.
Maybe if minus were defined
minus =. minus ` (minus~) ` + :. -
one could pull simplification stunts like
minus inv
+-----+
|minus|
+-----+

I dunno, this may be getting too messy.

Comments?

--

Fri, 11 Mar 1994 11:58:10 GMT  J: a little exercise

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   |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Fri, 11 Mar 1994 00:46:39 GMT  J: a little exercise

Quote:
> [] Getting late evaluation of the noun operands is not as easy as it looks.

> Try

> For example,
>    'name' late
> is a monadic function which always returns the current value of the
> pronoun 'name'.

That's what I was after. I'm still at 2.7, with [ and ` unimplemented,
but no rush.

One thing I will say, though: there's a word for languages where you have
to work out something ingenious to get as intuitive a mechanism as call-
time-binding, and the word is _low-level_ :-)

Quote:
> [] 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?

> The first is equivalent to
>      ((+"1 & ".) 'v')
> since conjunctions parse left to right.

Ah, of course. Thanks.

Quote:
> I'm not sure I understand what the semantics of [+"1/] are supposed to
> be, such that you can invert it.  Inverse doesn't have a functional
> meaning except with monads.

Sorry, I wan't thinking straight there. Inverse applies where you
perform one operation on however many items, as in (+"1 & v) x or
(v & +"1) x, where v is of rank 1. It doesn't make sense for cartesian
products.

[] 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.

Quote:
> Again, I'm not sure what is being said here.  Note that in 3.2 nouns
> are still evaluated greedily.  At a guess, though, you want something
> like.

>    example =. 'x f y' late

> which is a monadic verb which ignores its argument, but resolves the
> binding of 'x', 'f', and 'y' at the time that 'example' is passed an
> argument.

That's right.

Quote:
> [] 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'?

> The problem here is still that inverse doesn't understand about the
> obverse of a dyadic function.  This requires either a language change
> or that you define your own version of 'inverse'.  Other than that,
> all you're doing is defining new names for addition.

Not exactly. The problem is that we've made a machine for adding v
to all rank-1 cells of its operand, and now we want a machine for making
such machines. It seemed to me the two ways to do this were (1) to
write a string s(v) such that ''::s(v) is the machine we want, and
then a string-builder which substitutes whatever we want for v;
or (2) build something that reaches inside a verb and substitutes for
an internal constant or an internal verb.

(A fair retort would be "Go build your adders in Lisp". But I'm still
getting to grips with what J can do and can't, and being surprised.)

In this case, yes, it was unreasonable to couple two dyadics with the
:. conjunction, and expecting to get monadic inverses when I specialized
them to right or left with &. But the question of how much we can
abstract from a verb definition remains.

Later....

Quote:

>  It is generally true that if both
>     y = (x&G) (x&g) y
>     x = (G&y) (g&y) x
>  then G might be considered an 'dyadic inverse' of g.  Obviously, this
>  is not considered in the current versions of J.
> However, on consideration of the definition of CHAIN (f^:n, used
> dyadically), I think it would be better to make the conditions:
>   y = (G&x) (x&g) y
>   x = (y&G) (g&y) x
> for G to be considered a 'dyadic inverse' of g.

Nice try, but I've learnt my lesson. 'Dyadic inverse' is trying to get
inversions from positional information, and the inversions usually won't
be there. Consider:

Function        Inverse

+ & x               + & (-x)    Addition on right
- & x               - & (-x)    Subtraction on right

x & +               (-x) & +    Addition on left
x & -               x & -               Negation followed by addition on left

The inverse of + just isn't - in any consistent sense. Likewise, the
inverse of left matrix multiplication is just left multiplication again,
by the inverse matrix.

Thanks very much for your incisive comments.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Jonathan Burns        |

Computer Science Dept |
La Trobe University   |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Sat, 12 Mar 1994 00:22:53 GMT  J: a little exercise
Raul Rockwell:

Jonathan Burns:
[] That's what I was after. I'm still at 2.7, with [ and `
[] unimplemented, but no rush.

I think that for 2.7 you'd say

[] The problem is that we've made a machine for adding v to all rank-1
[] cells of its operand, and now we want a machine for making such
[] machines.

Try:
mm=. machine_maker=. '(x. late  + ]) :. ([ - x. late) "1' : 1

[I think I got the argument order for :. right this time.  Function on
the left, inverse on the right.]

For 2.7, that probably should be:
mm=. machine_maker=. '(x. late  + {:) :. (}: - x. late) "1' : 1

For example,
f =. 'v' mm
v =. 4
f i. 3
4 5 6
v =. i. 3
f i. 3
0 2 4

[] It seemed to me the two ways to do this were (1) to write a string
[] s(v) such that ''::s(v) is the machine we want, and then a
[] string-builder which substitutes whatever we want for v; or (2)
[] build something that reaches inside a verb and substitutes for an
[] internal constant or an internal verb.

Well, you could do it either of those ways, but the extra indirection
adds complexity.  Then again, as long as v is supposed to be a global
var, you could write
s =. 'y. + '&,

This isn't going to give you an invertible function, but if you define
g =. (s 'v') : ''
then you could say
g i. 3 3
0 2  4
3 5  7
6 8 10

[Though this might give an error under 2.7.  I don't remember when
vector extension began working for scalar verbs.]

[] But the question of how much we can abstract from a verb definition
[] remains.

Well, as a general rule, you're going to want to take a step back and
write the abstraction yourself.  There are many forms of abstraction.

--

Sat, 12 Mar 1994 09:54:57 GMT

 Page 1 of 1 [ 6 post ]

Relevant Pages

Powered by phpBB® Forum Software