I was amused by this: "Arguably it's the nicest programming environment I've ever used, even though I go back and forth about whether J itself is brilliant or insane."
http://prog21.dadgum.com/28.html In an unrelated conversation, someone I know complained about APL syntax, and I pointed out that the case he was talking about had no unusual syntax -- it was bog-standard expression syntax, just like any other language's expression syntax. It was just the symbols and their definitions being different. And, he said "yes" -- that when he said "syntax" he really meant the semantics. Meanwhile, in a completely different context, I was building some "flip" code for javascript. There are numerous jquery plugins that deal with "flipping" content -- giving an effect like rotating it on a 3d plane. But I wanted to be able to flip on an arbitrary axis. After a bit of investigation, I decided to use the css3 2d matrix operations -- that gave me compatibility with IE9, chrome, firefox and a few others (but not IE8, so users of windows XP would have to use something other than IE to get this effect). After struggling with various implementations, I finally fell back on how I would do it in J. Leaving out the jQuery animate stuff, the code looks like this: function do_rotate(target, axis, angle, X, Y) { var m= inner_product( translate(X, Y), inner_product( rotxy(axis), inner_product( rotyz(angle), inner_product( rotxy(-axis), translate(-X, -Y))))); var matM= cssmatrix(m, 1); var matG= cssmatrix(m, 0); target.css({ 'transform': matG, '-moz-transform': matM, '-ms-transform': matG, '-o-transform': matG, '-webkit-transform': matG }); }; function op(f, m1, m2) { var r= []; if ('object' != typeof m1) if ('object' != typeof m2) r= f(m1, m2); else for (var j= 0; j < m2.length; j++) r[j]= op(f, m1, m2[j]); else if ('object' != typeof m2) for (var j= 0; j < m1.length; j++) r[j]= op(f, m1[j], m2); else for (var j= 0; j < m2.length; j++) r[j]= op(f, m1[j], m2[j]); return r; } function add(m1, m2) { return op(function(x, y) {return x+y}, m1, m2); } function mul(m1, m2) { return op(function(x, y) {return x*y}, m1, m2); } function sum(m) { var r= 0; for (var j= 0; j < m.length; j++) r= add(r, m[j]); return r; } function inner_product(m1, m2) { var r= []; for (var j= 0; j < m1.length; j++) r[j]= sum(mul(m1[j], m2)); return r; } function translate(x, y) { return [[1, 0, 0, x], [0, 1, 0, y], [0, 0, 0, 1], [0, 0, 0, 1]]; } function rotxy(angle) { var c= Math.cos(angle); var s= Math.sin(angle); return [[c, -s, 0, 0], [s, c, 0, 0], [0, 0, 0, 1], [0, 0, 0, 1]]; } function rotyz(angle) { var c= Math.cos(angle); var s= Math.sin(angle); return [[1, 0, 0, 0], [0, c, -s, 0], [0, s, c, 0], [0, 0, 0, 1]]; } function cssmatrix(m, moz) { moz= moz ?'px' :0; return 'matrix('+[m[0][0], m[1][0], m[0][1], m[1][1], m[0][2]+moz, m[1][2]+moz].join(',')+')'; } And that was enough for me to get where I wanted to be. Here, function op() gives me the ability to have javascript functions which behave like J rank 0 dyadic verbs. And, inner_product is J's +/ .* as long as the left argument has a rank no greater than 2. (In real life, J's implementation is not so recursive -- I think that the recursion in op() has more to do with javascript's array data structures than with J.) Anyways, I think my point here is that everything J does is simple -- dead simple. It's difficult, though, sometimes, conveying just how simple this stuff is. -- Raul ---------------------------------------------------------------------- For information about J forums see http://www.jsoftware.com/forums.htm
