One interesting issue, here, is that the concise expression in J is
not because J was specifically optimized for this task, but because J
has so many expressions which can be used for this task.

But some people had expressed confusion, about how to read one of my drafts:

   f=:[:|:((i.|.-.)~(a.{~65 97+/i.26)&(*@#.@e.,@#[))"0

So I thought I'd spend a few moments going over its grammar.  This may
feel tedious if you have already figured out how that sentence works.

First, the top level grammar is:
   f=:verb

and you can test this, after you define f:
   nc<'f'
3

Here's the complete list of classes that a name can have:
3  verb
2  conjunction
1  adverb
0  noun
_1 undefined
_2 invalid name

And any [valid] parenthesized expression can be assigned to any
[valid] name and you can use nc to test what kind of value the name
refers to.

Here's how that verb breaks out, at the top level:

   [:    |:    ((i.|.-.)~(a.{~65 97+/i.26)&(*@#.@e.,@#[))"0

That's three verbs -- a fork.  (Basically all that's happening here,
is that I'm transposing the result, which is how I get the horizontal
vs. vertical arrangement in this implementation -- a single letter
argument will give me a 1 dimensional array which is unchanged by
transpose.)

Also, the rightmost verb has this grammar:
   (verb) conjunction noun

It's the inner verb here which is complex (and which you sort of have
to understand before the rest makes sense).

That inner verb looks like this:

   (i.|.-.)~    (a.{~65 97+/i.26)&(*@#.@e.,@#[)

In other words, it's two verbs -- a hook.  And remember: we always use
the dyadic definition of the left verb in a hook and the monadic
definition of the right verb in a hook.  (For forks, we always use the
dyadic definition for the "middle" verb of the fork but the
grammatical context of other verbs depends on the grammatical context
where the fork is used).

Anyways, the rightmost verb in this hook works like this:

   (a.{~65 97+/i.26)&(*@#.@e.,@#[) 'c'
abcdefghijklmnopqrstuvwxyz

It's a lower case alphabet if the argument is lower case, an upper
case alphabet if the argument is upper case, and blank otherwise.

The left verb works like this:

   'c' (i.|.-.)~ 'abcdefghijklmnopqrstuvwxyz'
defghijklmnopqrstuvwxyzab

or we can get rid of that cross adverb, swapping the arguments:

   'abcdefghijklmnopqrstuvwxyz' (i.|.-.) 'c'
defghijklmnopqrstuvwxyzab

And, of course, we can break it down further:

   'abcdefghijklmnopqrstuvwxyz' i. 'c'
2

   'abcdefghijklmnopqrstuvwxyz' -. 'c'
abdefghijklmnopqrstuvwxyz

In other words, it's removing the 'c' from the alphabet and rotating
the leftmost two characters onto the righthand side.  (You can try out
the |. for yourself...)

That only leaves this verb:

   (a.{~65 97+/i.26)&(*@#.@e.,@#[)

which (if you nave linear display representation turned on) J shows as:

(2 26$'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz')&(*@#.@e. ,@# [)

So it's a noun (the two alphabets) which is the left argument to the
verb (*@#.@e. ,@# [)

And remember that this whole thing is inside that (verb)"0 construct,
so we will only ever see a single letter here.

The left tine of the fork is *@#.@e. and this tells us which alphabet
our argument character is in.

   (a.{~65 97+/i.26) *@#.@e. 'a'
0 1
   (a.{~65 97+/i.26) *@#.@e. 'A'
1 0
   (a.{~65 97+/i.26) *@#.@e. '-'
0 0

If we strip that down to just the e. it looks more like this:

   (a.{~65 97+/i.26) e. 'a'
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

But #. will interpret each row as a binary representation of an integer:

   #.(a.{~65 97+/i.26) e. 'a'
0 33554432

And, * will tell us the sign of that integer (it's 1 or 0)
   *#.(a.{~65 97+/i.26) e. 'a'
0 1

Hopefully, the rest is obvious...

-- 
Raul
----------------------------------------------------------------------
For information about J forums see http://www.jsoftware.com/forums.htm

Reply via email to