news@usc.edu (09/20/90)
J is a fairly recent dialect of APL, greatly simplified in several respects, and significantly enhanced in some others. It includes improvements slated for inclusion in APL dating, in some cases, all the way back to the 60's. I've been playing with version 2, which is not quite complete, and has a clunky user interface, but I've been quite impressed. If you're not interested, hit 'N' now. J as a functional language (e.g. along the lines of scheme): J has 0 keywords, and will take arguments from both sides of a function, but if you don't mind the restriction, you can make it look remarkably like scheme: o =. 0 0$'' }:' "nothing" -- very useful :-)' read =. 1!:1 }:' associate name with system call' set =. (read 1)::'' }:' scheme-like set' (y. , '=: y.')::'' }:' function which assigns data to name' indirect =. (read 1)::'' }:' converts 2 arg fns into a 1 arg form' (y. , '& y.')::'' plus =. indirect '+' first=. indirect '{.' rest =. indirect '}.' o}:' use of the above definitions:' ((set 'foo') 1 2 3 4 5) 1 2 3 4 5 (first foo) 1 (rest foo) 2 3 4 5 ((plus 8) foo) 9 10 11 12 13 Their are, of course, a number of differences between J and scheme. For example, if you wanted a structure more complicated than a simple list of numbers or list of characters, you would need to use one of J's structure building functions: (rest 'foo';'bar';'bletch') .---.------. |bar|bletch| '---'------' The boxes indicate that the enclosed lists (of characters) are being treated as scalars. The semicolons indicated that I wanted the strings boxed and linked together in a list. The parser is, well, very minimalist--roughly equivalent to LL(4)--and available as a primitive function. Evaluation and parsing are synonymous. (The lexical analyzer is also extremely simple, and available as a primitive function.) Also, for those of you not familiar with apl, the parser runs right to left instead of left to right. J words fall into one of 6 syntactic classes: Punctuation (left and right parenthesis) Copulae (local assignment and global assignment) Adverbs and Conjunctions (roughly equivalent to declarations) [imperative] Verbs (functions) Nouns (data) Adverbs are distinct from conjunctions because they have different syntax. Primitive adverbs and conjunctions all appear to yield verbs as their result. Primitive functions all yield nouns. Names can be assigned any type of word, except punctuation. For example: test =. / a =. + is =. =. this is a test this 1 2 3 'test' became an adverb, 'a' became a verb, and 'is' became a copula. 'this is a test' assigned to 'this' the derived verb '+/' which has the effect of placing the function '+' between each of the array cells of its argument. J differs from most other dialects of APL in a number of ways. J is, for example, statically scoped. Also, it has 'phrasal forms' where several functions can be combined to form a single function. For example: 3 (+,-,*,%) 2 5 1 6 1.5 Note that '*' means multiplication, and '%' means division. If you ask J to evaluate something which evaluates to a function, it will show you the tree structure it uses to represent that function: +,-,*,% .-.-.-------------. | | |.-.-.-------.| | | || | |.-.-.-.|| |+|,||-|,||*|,|%||| | | || | |'-'-'-'|| | | |'-'-'-------'| '-'-'-------------' (That looks a lot better if you use the pc's line drawing characters... oh well..) Basically, in a phrasal form, like the above, the left and right arguments to the derived function go to each the 'odd' functions, and the results of those functions go to the 'even' functions. So the above example is equivalent to: (3+2),(3-2),(3*2),(3%2) and yields the same result: 5 1 6 1.5 I haven't seen anything like this in any other computer language, so it should look quite foreign to most of you. I suppose the point I'm trying to get across is that J allows an extremely wide range of expressiveness. Enough that style becomes MUCH more important than substance... J is supposed to be available in a freely redistributable form for PCs, Macs, NeXT machines, MIPS, VAX, and a handful of others (e.g. sun3 and sun4.. but that particular version is still vapor). Check with the comp.lang.apl newsgroup for specifics of what versions are available, and from where. I know the pc and mac versions are available for anonymous ftp from watserv1.waterloo.edu. Documentation, at present, is pretty skimpy. There is supposed to be a book available, but I haven't received my copy yet. The best I can recomend is print out all the text files that come with the distribution, and try the examples. Documentation on APL, and past issues of ACM's SIGAPL journal (Quote Quad -- look for anything written by Ken Iverson. I think volume 18, No. 1 is probably the best mine of information) can give you some hints. If there is enough interest, and if I can access the net, I'll post more, later. Oh yeah, by the way, if you use the 'read' function I defined towards the begining of this post, and you want to read multiple lines, the notation is: read 1 1 1 to read 3 lines. You can make this more stylistic by defining a sort of a bastardized adverb ('bastardized', because it is meant to return a noun, not a verb) as follows: lines =. 1::(read 1) x. $ 1 This allows you to say: read 3 lines instead of (read 1 1 1) -- I'm posting from raulmill@usc.edu, but this account is slated to be disconnected within about a week.
news@usc.edu (09/21/90)
Shortly after I made the earlier posting <12061@chaph.usc.edu>, I realized I had made several mistakes, including a couple program bugs. First off, I should have said first =. {. and rest =. }. as each of these functions take only one argument, and giving them two arguments only confuses the matter. Secondly, I should have explained my notation a little better. Explanation follows (long) Lines that were indented three spaces, such as o =. 0 0$'' were lines intended to be typed into the J command line interface. Unindented lines which immediately followed were usually the function results (except where I was using the 'read' function.. there they indicated input to be read. Also, I mixed in free text, but I hope that was obvious). Second, the J lexical analyzer would parse o =. 0 0$'' like this: .-.--.---.-.--. |o|=.|0 0|$|''| '-'--'---'-'--' Generally, anything followed by a . forms a two character token. Non alphabetics followed by a : also form two character tokens. After than, numeric lists (where each element begins with a digit, such as 2e or 4j) formed into tokens, as are ' delimited character strings, and fairly typical alphanumeric symbols. =. indicates local assignment $ y gives the shape (dimensions) of y x $ y returns a new array containing array cells from y, arranged with the dimensions given in x !: is the 'system call' interface (and is syntactically a conjunction) I forget whether I mentioned that adverbs only take their arguments from their left, and conjunctions take an argument on both the left and right side. Also, because of priority, adverbs and conjunctions can take either verbs or nouns as arguments, while verbs can only take nouns as arguments. x }: y returns x :: is the generic definition conjunction x , y catenates x and y to form a longer list & is a conjunction that sticks two verbs together to form a single verb, or sticks a noun and a verb together to form a verb. e.g. (-&3) 4 would return 1 {. y returns the first array cell in y }. y returns all array cels but the first in y y. is the right argument passed to something defined by :: x. is the left argument incidentally, in a definition like string1::string2, the string1 definition is used when there is only one argument available, and the string2 definition is used where their are two nouns available. (and a character matrix or a list of strings would work here just as well as a simple string). =: is for global assignment. I used this for 'set', because local assignment is trickier (you have to evaluate it in the right context), and the feature that I would have used to make this work is not implemented in version 2. x ; y will 'box' y, if it is not already boxed, and it will box x, and then it catenates the boxed version of x onto the front of y. Although I didn't mention it, if you just want to box a single object, you can do it with (< y). Boxing is roughly equivalent to C's & operator--you are effectively taking a pointer to the object. Unboxing, which may be done with (> y) is roughly equivalent to C's * operator, except that if y is an array of boxed objects, the newly unboxed elements are padded to make them all the same size, and the result is a new array with extra dimensions on the end, to hold these new elements. I could go on, but I ought to stop somewhere...