42 lines?
If this interests you at all, absolutely worth reading Roger Hui's retrospective on the subject (more about J + Ken Iverson, but definitely fascinating) http://keiapl.org/rhui/
42 lines?
If this interests you at all, absolutely worth reading Roger Hui's retrospective on the subject (more about J + Ken Iverson, but definitely fascinating) http://keiapl.org/rhui/
On the other hand, it's notable that many IOCCC submissions happen to pack a lot of functionality in often less than 2k. I remember reading a few descriptions of some the winning entries, but I can't find that now. Here's a glimpse though: http://cboard.cprogramming.com/brief-history-cprogramming-co...
If you become inexplicably fascinated by that code and want help unraveling it, my contact info is in my profile.
I don't consider it noteworthy as a useful program under 2kloc (on modern hardware it usually just crashes, it's quite cavalier with pointer casting, and clearly a quick prototype either way), but it's like a pink space laser beam of insight about the APL mindset. Real APLs take more than a page, but not that much more. Eliding loops does that.
A lot of the IOCCC code is also delightfully perverse, too. Highly recommended.
I showed this fragment to others in the hope of interesting someone competent in both C and APL to take up the work, and soon recruited Roger Hui, who was attracted in part by the unusual style of C programming used by Arthur, a style that made heavy use of preprocessing facilities to permit writing further C in a distinctly APL style.
Also, the APL community seems to be pretty disjoint from the rest of CS (though Arthur is also a Lisper). I think it'd be mutually beneficial if the APLers and the MLers got together, in particular.
I would disagree. That code is beautiful. Elegance and brevity; it's as close to a pure expression of the coder's thoughts as it's reasonably possible to get.
It was a quick prototype written by one APLer, for another APLer, using mutually understood conventions. For example, its dyadic verbs ("V2" functions) use the variable names 'a' and 'w'. For a while, I wondered why (maybe they stood for "Arthur" and "Whitney"?), but after reading Iverson's _A Programming Language_, I realized APL usually uses lowercase alpha (α) and omega (ω), which look like 'a' and 'w' in ASCII. Details like that would need no explanation.
Likewise, in
typedef struct a{I t,r,d[3],p[2];}*A;
t is type (is it boxed? 0 or 1), r is rank (number of dimensions), d is the dimensions (hardcoded to a max of 3; a 2x3x4 matrix has d={2,3,4}), and p is a variable-length array sized by malloc-ing extra space; that's where the values go, either longs or void pointers). That'll save you some time if you ever try to pick the rest apart. :)APL code is often terse to the point of seeming cryptic, just math papers are. You get used to it, and it's that way for a reason.
My immediate reaction on seeing the page was recoil and puzzlement: it looked nothing like any C code I had ever seen. (“Is it even C?”) However, Ken counselled that I should reserve judgment. As recounted in An Implementation of J, it then happened that:
I studied this interpreter for about a week for its organization and programming style; and on Sunday, August 27, 1989, at about four o’clock in the afternoon, wrote the first line of code that became the implementation described in this document.
The name “J” was chosen a few minutes later, when it became necessary to save the interpreter source file for the first time.
Like Emacs, J's internal documentation is excellent, but you have to learn its idiosyncratic terminology before you can actually find things.
I, for one, am happy simply finding the code 'of interest'. It's not great code, it's the initial sketch of an idea (I'll bet you AW would admit that readily (plus Roger Hui refers to it as "Incunabulum", which seems a bit tongue in cheek)) -- but, it's certainly not something you see every day, and it is thought provoking.
I do recommend studying it, though. Their APL dialects are really something; I wish there were good fully open-source implementations, and writing one is on my queue. Kona (http://github.com/kevinlawler/kona), an open-source implementation of K 3.2, is also coming along.
Just be warned that APLer C is usually nasty, brutish, and short. :)
FWIW, the best thing I've seen for getting the J mindset is _J for C Programmers_ - as Henry Rich says, to do J you must "think big" - don't think "for each part of this list, do this, then this, then this...", think, "apply this operation over these.". That scales up to multiple dimensions, and can often be run in parallel. :)
I'm going to save this for the next time someone asks why there aren't more females in CS/programming. I just tell them that this kind of code is held in high esteem, instead of being ridiculed for the stupidity that it is.
As for obfuscation, it's rather straightforward -- it's just concise. A lack of instant understanding doesn't indicate that a piece of code is without merit, or not honest and straightforward.
I get this person may have been working with constraints we don't know about, but its not straightforward. Give this to 10 working C devs and ask them to tell you what it does without running it.
The standard cues of straightforward code aren't there -- well named variables, well named functions, comments, indentation, etc...
The APL people are not fooling around, either - look at Kx's customers: http://kx.com/Customers/end-user-customers.php . And then check how much a license for kdb+ costs per core. Oh, and "a standard purchase requires licensing at least 8 cores."
I'm curious, do you think you could tell me what some arbitrary C code does that I give you, where I've changed all the variables to "a", "b", "c", etc...? I'd be hardpressed to believe anyone in the world could.
Is APL structurally so expressive that huamns can easily extract meaning from structure? If so this is the single great accomplishment in the history of computer science. This dwarfs any contribution from Lisp, C, FORTRAN, theory of computation, etc...
And the fact that I know some of the people that worked on the original versions of APL at IBM, yet they never mentioned this, makes me suspect.
If you know the specific context ahead of time (a FSM for lexing, a hash table implementation, etc), then it really isn't that hard.* Are you honestly telling me that you wouldn't be able to figure out how a hash table implementation worked if all the types and variable names were changed to single letters? It would slow you down, sure, but it wouldn't be impossible.
* Speaking as someone who has debugged code with variable names and comments in Swedish.
That code was written with the context of, "Hey, we both know APL really well, here's a quick prototype for a new implementation of it, could you give it a look?" When somebody is showing a Scheme implementation to other Lispers, they don't need to spend time explaining what a cdr is. Context matters.
Most of the functions in that take one or two arbitrarily-dimensioned arrays and loop simple operations over them. Everything takes (w) or (a, w) and returns z. i is a loop index (as usual). w->p is the array of values in w, ga allocates a new array. ("get array"? "generic allocate?")
V1(iota){I n=*w->p;A z=ga(0,1,&n);DO(n,z->p[i]=i);R z;}
iota (the term comes from APL; J uses "i.", K uses "!", Q uses "til") takes a number and returns a vector of integers from 0 to n. iota 5 -> 0 1 2 3 4. Most of the definitions are equally simple, there just isn't much whitespace. DO is a macro that abstracts out the common "for (i=0; i<n; i++) { ... }" loop, which is used all over the place.Yes, probably not. I've looked at code that I've personally written with variable names -- in the debugger and still scratched my head trying to figure out what I had done. And not trying to overstate my ability, but I tend to be someone who is generally pretty good at reading code.
Here's some code you might run across in some DSP code. There are some globals, and hopefully I translated it correctly. But in any case, w/ good function variable naming I could understand the intent in a few seconds. Without it, I think I'd scratch my head for some time. How long does it take you to figure out what it does (or what it is intended to do)?
ov f(){
xx b, hh, i, pp, j, jj = PL, k;
xx D = NN>>2*b,d=n-2*zz;
t *z[B]; t *p, m, n, q, oo;
for (i=0; i<B; i++) z[i] = &X[ro[i]*jj];
for (b=0; b<D; b++) { f(b, hh, d);
for (i=0; i<B; i++) { pp=ro[i];
k = (b << zz) + i;
p = &YY[(hh<<zz) + (pp<<(n-zz))];
for (j=0; j<B; j+=SS) { m = z[j][k];n=z[j+1][k];q = z[j+2][k];oo = z[j+3][k];
p[j]=m;p[j+1]=n;p[j+2]= q;p[j+3]=oo;}}}}About your code sample - I haven't done anything with digital signal processing code, so I couldn't tell you. It looks like some sort of wave transformation, but that's like saying code from a 3D rendering engine is "doing something with triangles", sorry.
Most of the APL functions are only a line or two long, though - that makes a big difference. "accumulate i..N", "get new vector with a[i] + w[i]", etc. The only part that is individually complex is the parser.