feustel@netcom.COM (David Feustel) (03/17/91)
I'm new. What's J? Is source available? What machines and OS's does it run under? Thanks. -- David Feustel, 1930 Curdes Ave, Fort Wayne, IN 46805, (219) 482-9631 EMAIL: netcom.com
cs450a03@uc780.umd.edu (03/17/91)
David Feustel: >I'm new. What's J? Is source available? What machines and OS's does it >run under? Thanks. Hi, This may be restating the obvious, but J is a programming language. It is, I think, more than a little elegant. The current incarnation is probably what you'd call a beta-version. It's not quite fully implemented, and could stand some real speed improvements. (It is, however, infinitely faster than vaporware.) Source, sadly, is not available. Though if the GNU people get rich enough the Iverson Software people may follow in their footsteps. (Iverson Software Inc. is the group writing/providing the interpreter.) As for what machines it runs on, memory tells me pcs, sun4s, bsd-vaxen, mips machines, and I believe next machines and macs, and probably others. Ftp 129.97.129.140 (I think that's watserv1.waterloo.edu), /languages/apl/j ... subdirectory by architecture, for binaries. If other machines than these are supported, I'm sure the ISI people will be happy to tell you. Slight problem... there isn't much in the way of on-line docs for J. I'm not sure how such docs fit in with ISIs philosophy... Currently, if you send them $24, they'll send you docs and a copy of their latest version of the software... If you can tolerate dense information, the binaries come with a complete list of commands (indicating what's implemented), and detailed docs on each of the system commands. There are also about 40 screens worth of example code, grouped by subject. There's also a little custom previewer to look at the example code. Following is a quicky example (something I was playing with earlier today). I didn't write it for anyone else, so it has only one (useless) comment, but I'll try and add some docs at the end. Example (uuencode) follows... $ j J Version 2.9 Copyright (c) 1990 1991, Iverson Software Inc. 2!:4 <'uu.jws' 1 uul +---------+--+----------------------------------------------------+ |(#y.)$:y.|::|uunum =. #. ((4 * >. x. % 3),6) $, (8#2) #: a. i. y.| | | | a. {~ (32 + x. , uunum), 10 | +---------+--+----------------------------------------------------+ uul 'foobar' &9F]O8F%R uuenc +--------------+--+-------------------------------------------------+ |'644 file'$:y.|::|nl=. 10 { a. | | | |'mn'=. 0 45 #: # y. | | | |begin=. nl,'begin ',x.,nl | | | |end=. (uul ''),'end',nl }: 'requires uul' | | | | begin, (,uul"1 (m,45)$y.), (uul (-n){.y.), end| +--------------+--+-------------------------------------------------+ uuenc 'This is a test, This is only a test. If it weren''t a test.....' begin 644 file M5&AI<R!I<R!A('1E<W0L(%1H:7,@:7,@;VYL>2!A('1E<W0N("!)9B!I="!W 297)E;B=T(&$@=&5S="XN+BXN end (Incidentally, I hope you have a way of splitting your screen to read this, otherwise I guess you'd have to print it out...) First, programs name is 'j', you get that banner every time you start, and the default prompt is three spaces. Second, that 2!:4 is a raw system call. Library 2 is workspaces (J will allow you to manage objects on file by name, if you'd rather that than raw character data). Call 4 happens to be a read command. The file I wanted to load was called uu.jws, and since the call needs a pointer to a string, < makes one (kind of like * in c). The 1 is a return code indicating success. Most people consider this sort of thing gory, and make themselves a profile file to provide nice covers for system calls and such. I don't bother, because I've been using J on a guest account, and everything gets blown away every few days. The routine 'uul' takes a line of up to 45 characters and returns the corresponding line of uuencoded garbage. Quick summary: :: says this is a verb (function). The string on the left is the verb's intransitive form (takes only one argument). The string on the right is the verb's transitive form (takes two arguments). $: is a self reference (by the verb, to itself). Normally, it's used for recursion, here I was playing around with the idea uuencode, and thought I might want to claim that a string had some length different from what it really had. So the transitive form takes a left argument of the strings 'intended' length. y. is the right argument to the verb. In the transitive case, x. is the left argument. # counts how many elements are in a list (or string) when used intransitively, and if used transitively the left argument says how many copies to make. a.i.y. converts an ascii string into numeric form. (a. is the ascii character set, with ascii character 0 in position 0, ascii character 1 in position 1, etc.) i. looks up each character and returns the indices (which are the ascii codes). #: converts from number to a list of digits which represent that number. The eight 2's mean I get 8 bits (base 2 digits) for each number. The , (used intransitively) means ignore the structure of the array that #: generated. This is important because $ (used transitively) gives it a new shape: Instead of 8 columns, it will now have 6, and to make up for than, I increase the number of rows by a third. % is division, so x. % 3 is one third the original length. >. raises that value to the next highest integer (if it's fractional). 4 * ... multiplies by four. #. converts from the base two representation back to a list of numbers. These numbers each will be encoded as characters on the next line. =. is an assignment statement. It localizes the name on the left too. On the next line, (,) is used transitively to catenate the number of characters represented onto the beginning of the line. Then all these numbers are offset by 32, to avoid control characters. A 10 is added onto the end (ascii 10 is newline). Then the numbers are converted to ascii. a.{~y is roughly equivalent to the C statement a[y], except that it works on all the data you specify. Thus, a.{~ 102 111 111 would return the three character string 'foo'. (By the way, ~ means swap the arguments (give the right argument on the left, and the left argument on the right) 102 111 111 { a. would also yield 'foo'.) The last line executed in a verb gives that verb's return value. It is unfortunate, I suppose, that you can't tell from the display that the intransitive form of uul has only a single line. Still with me? I suppose it should be apparent by now that a single line in J will often hold as much meaning as a full screen of text in a number of other languages. It would be a mistake to try and read over J by simply glancing at a page and expecting to get the gist of what's going on in a couple seconds. Or, not at first at least. If you can get used to reading one line as carefully as you would a number of lines in lisp, or modula, or whatever, you should find that it is just as understandable. Of course, it's alway handy to have a computer at hand to see what each part of a statement does to representative data. I tried a short example of uul, not to attempt to show how it functions (to do that, you'd want to do something a bit more step-by-step), but to compare with the results of uuencode. The garbage looked the same, so I wrote a cover to handle the larger parts of the uuencode format. The intransitive form of uuenc is very similar to the intransitive form of uul: In this case I'm providing a default header (file access privileges, filename) argument so I don't have to worry about that for testing. First, since I was using more than one instance of the newline character, I stuffed that into a variable. Second, since uuencode puts out 45 characters per line (except for the last line), I convert the number of characters in the argument string to a two digit 'base 45' number. (Well, sort of.. that leading 0 means the leading digit can be as large as necessary to hold the result, it is not cut off arbitrarily at 44). The string 'mn' that I assign into means variable m gets the first number (the number of whole lines to be converted), and the variable n gets the last number (the length of the last, partial length line). J uses two quotes when quoting variables, instead of a single quote (like lisp does), and allows a shortcut (which I use here) when using variables with single character names. If I wanted to be really formal, I would have written: ('m';'n') =. 0 45 #: # y. Or, I could have gone further and computed the quotient on one line, and the remainder on another. Incidentally, it just occurred to me to wonder if uudecode will choke if there are two terminating lines (nl,' ',nl,' ') between the last line of garbage and the 'end' string. I don't think it will, but feel free to test for that condition. Ok, the third line of uuenc constructs the header. Nothing really but simple string catenation. The fourth line constructs the ending sequence. uul applied to an empty string simply returns a space and a newline, but I was feeling a touch formal when I wrote this. If it turns out that uudecode chokes with two blank lines at then end, I'd throw a test in here to get rid of the space,newline when it isn't needed. Finally, I put all the pieces together and return that as the function result. Starting in the middle, (m,45)$y. converts the argument string into a table of characters where each row is 45 characters long. Usually this table is slightly smaller than the original string and a few characters get dropped off the end. uul"1 means that I am passing to uul individual strings (i.e. one dimensional arrays). J automatically executes uul once for every row, and puts together the result into a single array. After that, I use the intransitive (,) (called ravel) to throw away all the details of the array. After all, my result is intended to be just a string. (-n) {. y. grabs whatever would get left out of that big array and runs it through uul separately. I think this is important, because the manual pages on uuencode didn't seem to permit a lot of padding at the end, at least not before the end marker. To test this out, I ran a few strings through uuenc, stuffed them out to file, and then ran uudecode on them. The basic concept looks good (no bit-reversal problems or anything like that). I think this is an order of magnitude slower than uuencode, but it is at least somewhat educational. And, who knows, maybe with future versions of the interpreter speed for things like this will increase drastically. (Not entirely an unreasonable idea. I found that on a 16Mhz 386, with a version of J from last October, I was getting about 2 milliseconds per integer addition (that's trying things like x + y where x and y each had a thousand integers in them). Like I said earlier, quite a bit faster than vaporware. But still well below what I expect the performance ceiling to be. uuenc, on a rather loaded sun4, generally took what seemed like a couple seconds to run through a 5 lines message. Of course I didn't actually time it, and I was experiencing some pretty heavy-duty transmission lags (around a second or two between hit return and see response for just about everything), but that's internet for you. Raul Rockwell P.S. This has gotten long, sorry about that.
cs450a03@uc780.umd.edu (03/17/91)
I just re-read my last post. It has an embarrasingly large number of typos (I knew I should've proofread it before I posted...). If the language is too muddy for anyone, write me. I'll email a clarification. If I get many queries, I'll post too. Raul