CoffeeScriptが楽しい

知ってはいたけど自分では書いたことがなかった CoffeeScript。上のほうにある "TRY COFFEESCRIPT" ってやつを押すと、リアルタイムで CoffeeScriptJavaScript に変換して実行もできる。

Ruby + Python を2で割ったようなシンタックスで、ヒアドキュメントやら Range やらの構文や、最後の値とか if 等で計算した値をよろしく return してくれたり、痒いところに手が届きまくりで JavaScript を書くときのアノ苦痛が激減する。面白いと思ったのは、ループが while しかなくて、while は計算結果の配列を返す式というところ。式なので関数に渡したりできる (まあそれをやると生成した JS が見るに耐えなくなるけど)。

1.0 になるまでは構文に変更があるかもしれないので遊び程度に思っていてねと書いてあるけど、生成される JS は JSLint に通されるので、変数がグローバルに漏れることがなかったり、ある意味普通の JS を書くより安全かもしれない。

ついつい遊んでしまったのでペタリ。

# map するための配列
ary: [0...25]

# 普通の fibonacci
fib: (n) ->
  if n <= 1
    1
  else 
    fib(n-1) + fib(n-2)

# ベンチ
t: new Date()
res1: ary.map(fib)
t1: new Date() - t

# メモ化 fibonacci
fib: (->
  mem: []

  mfib: (n) ->
    if n <= 1
      1
    else 
      mem[n]: (mem[n-1] || mfib(n-1)) + (mem[n-2] || mfib(n-2))
)()

# ベンチ
t: new Date()
res2: ary.map(fib)
t2: new Date() - t

# 結果
if res1+''==res2+''
  alert "naive: $t1, memo: $t2"
else
  alert 'algorithm error'

↑これが↓こうなる。

var _a, ary, fib, res1, res2, t, t1, t2;
// map するための配列
ary = (function() {
  var _b, _c, _d, _e;
  _b = []; _d = 0; _e = 25;
  for (_c = 0, _a = _d; (_d <= _e ? _a < _e : _a > _e); (_d <= _e ? _a += 1 : _a -= 1), _c++) {
    _b.push(_a);
  }
  return _b;
}());
// 普通の fibonacci
fib = function fib(n) {
  if (n <= 1) {
    return 1;
  } else {
    return fib(n - 1) + fib(n - 2);
  }
};
// ベンチ
t = new Date();
res1 = ary.map(fib);
t1 = new Date() - t;
// メモ化 fibonacci
fib = (function() {
  var mem, mfib;
  mem = [];
  mfib = function mfib(n) {
    if (n <= 1) {
      return 1;
    } else {
      mem[n] = (mem[n - 1] || mfib(n - 1)) + (mem[n - 2] || mfib(n - 2));
      return mem[n];
    }
  };
  return mfib;
})();
// ベンチ
t = new Date();
res2 = ary.map(fib);
t2 = new Date() - t;
// 結果
res1 + '' === res2 + '' ? alert(("naive: " + t1 + ", memo: " + t2)) : alert('algorithm error');

VimEmacs 用のシンタックスハイライトもあるけど、それに加えて生成した JS を横に並べてくれる機能が欲しいところだな。


(Range の部分、ちょっと非効率だな。Mozilla のナントカモンキーならコンパイル時に最適化されそうだけど。Google Closure Compiler も最適化してくれるかな?)