JavaScriptをS式で(parenscript)

S式でJavaScriptを書けるライブラリ Parenscript。全部S式じゃないと嫌だっていう欲張りな貴方にピッタリ!ゆるふわ括弧な愛されWEBアプリが作れます!

実際のところ、letter: Parenscript で jQuery を使う場合は chain をで見かけて興味はあったけど今まで使わなかった。ので、Hackathonの時に書いたJavascriptをParenscriptで書き直してみたのでした。

Hackathonで書いていた JavaScriptはこんな有様。

var x = 0;
var y = 0;
var dx = 1;
var dy = 1;
var img = new Image();
img.src = 'http://www.lisperati.com/lisplogo_alien_128.png';
setInterval('draw()', 5);

function draw() {

    var w = 128;
    var h = 75;
    var canvas = document.getElementById('alien-canvas');
    if( !canvas || !canvas.getContext) {
        return false;
    }

    var ctx = canvas.getContext('2d');
    ctx.fillRect(0, 0, 500, 500);
    if(x + dx + w <= 500 && 0 <= x + dx) {
        x += dx;
    }
    else {
        dx *= -1;
    }

    if(y + dy + h <= 500 && 0 <= y + dy) {
        y += dy;
    }
    else {
        dy *= -1;
    }

    ctx.drawImage(img, x, y);
}

酷いですね。
やっていることは座標 x, y、移動量dx, dy、描画する画像を用意して 5ms間隔でdraw関数を呼び出し。draw関数は x座標に dx, y座標に dyを足して動かして描画する。画面から飛び出しそうになったら移動量の符号をを逆転させる。

以下がParenscriptで書いたコード

(ps (defvar x 0)
    (defvar y 0)
    (defvar dx 1)
    (defvar dy 1)
    (defvar img (new -image))
    (setf (@ img src) "http://www.lisperati.com/lisplogo_alien_128.png")

    (set-interval "draw()" 5)

    (defun draw ()
      (let ((w 128)
            (h 75)
            (canvas ((@ document get-element-by-id) "alien-canvas")))
        (if (or (not canvas) (not (@ canvas get-context)))
            (return false))
        (let ((ctx ((@ canvas get-context) "2d")))
          ((@ ctx fill-rect) 0 0 500 500)
          (if (and (<= (+ x dx w) 500) (<= 0 (+ x dx)))
              (setf x (+ x dx))
              (setf dx (* dx -1)))
          (if (and (<= (+ y dy h) 500) (<= 0 (+ y dy)))
              (setf y (+ y dy))
              (setf dy (* dy -1)))
          ((@ ctx draw-image) img x y)))))

そして評価後

var x = 0;
var y = 0;
var dx = 1;
var dy = 1;
var img = new Image;
img.src = 'http://www.lisperati.com/lisplogo_alien_128.png';
setInterval('draw()', 5);
function draw() {
    var w = 128;
    var h = 75;
    var canvas = document.getElementById('alien-canvas');
    if (!canvas || !canvas.getContext) {
        return false;
    };
    var ctx = canvas.getContext('2d');
    ctx.fillRect(0, 0, 500, 500);
    if (x + dx + w <= 500 && 0 <= x + dx) {
        x += dx;
    } else {
        dx *= -1;
    };
    if (y + dy + h <= 500 && 0 <= y + dy) {
        y += dy;
    } else {
        dy *= -1;
    };
    return ctx.drawImage(img, x, y);
};

JavaScriptCommon Lispで書けるなんて嬉しいですね。

  • psの中がJavaScriptになる
  • 大文字で出力すべき文字の前に "-"を置くと出力される識別子では大文字になる 例) get-element-by-id -> getElementById
  • JavaScriptの関数呼び出しは、LISPの関数呼び出しと同じ
  • let, let* などで局所変数を作れる
  • setfで変数に代入
  • @ は 第1引数.第2引数 という識別子として出力。これ単品ならプロパティ参照、もう一つ括弧で囲むとメソッド呼び出しになる