CoffeeScriptで話すように素数しながら考えた

久しぶりに素数シリーズをやりたくなる言語に出会いました。
CoffeeScript http://jashkenas.github.com/coffee-script/

PythonRubyScalaとmlが混ざったような言語でプログラミングして、それをJavascriptにコンパイルします。
なんだJavascriptならかなり高級言語だし自分で書けるじゃん、と思った方はこちらをご覧あれ。

Array::fold = (f, init)->
  c = init
  for e in this
    c = f(e, c)
  c
    
if Array::reduce is undefined
  Array::reduce = (f) -> @[1..].fold(f, @[0])

sum = (a)->
  a.reduce (e, c) -> e + c

alert sum([1..20]) #...shows 210

これは1から20の合計をたたみ込みで求めるサンプルコードです。プロトタイプ拡張も配列のスライスも、そしてなにより関数の記述と範囲リテラルもありそうです。@でthisにアクセスしていたりします。ちなみに構文構造化はインデント厳守なPythonふうで、改行文字はRubyのように構文上有意なトークンです。関数コールの括弧省略もRubyScalaに似ています。

これで生成された Javascript のコードがこんな感じ。

var sum;
Array.prototype.fold = function(f, init) {
  var c, e, _i, _len;
  c = init;
  for (_i = 0, _len = this.length; _i < _len; _i++) {
    e = this[_i];
    c = f(e, c);
  }
  return c;
};
if (Array.prototype.reduce === void 0) {
  Array.prototype.reduce = function(f) {
    return this.slice(1).fold(f, this[0]);
  };
}
sum = function(a) {
  return a.reduce(function(e, c) {
    return e + c;
  });
};
alert(sum([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]));

これ、先入観なしで見ると人が書いたようなムダのないjavascriptですよね。でもいちどコンパイル前のcoffeeを見てしまうと、こんなJavascriptですら低級言語に見えます。

さてじゃあ、素数を求めてみましょう。


パフォーマンスやメモ化を気にしない基本形

is_prime_number = (n)->
  (m for m in [2...n] when n % m == 0).length == 0

prime_numbers_until = (lim)->
  n for n in [1...lim] when is_prime_number n

alert (prime_numbers_until 100 + 1)


パフォーマンスやメモ化を意識して素数を求めた場合

exists = (es, cond)->
  for e in es
    if cond e then return true
  false

memoize = (f)->
  memo = {}
  return (x)->
    if memo[x] is undefined then memo[x] = f(x)
    memo[x]
    
is_prime_number = memoize (n)->
  !exists (prime_numbers_until n), (m)-> m != 1 and n % m == 0

prime_numbers_until = (lim)->
  n for n in [1...lim] when is_prime_number n

alert (prime_numbers_until 100 + 1)

それぞれは以下の2つのエントリで書いたプログラムにだいたい対応します。
話すようにプログラムするPythonチュートリアル - なんたらノート 第二期
続・話すようにプログラムするPythonチュートリアル - なんたらノート 第二期

http://jashkenas.github.com/coffee-script/ の TRY COFFEESCRIPT にコードをペーストすると、本当はどれだけjavascriptを書かないといけなかったかを知って驚くと思います。

とりあえず動くプログラムを書くところまでやってみて、そのRuby並の記述性の高さに驚きです。で、そのうえそれがPythonに似た(Javascriptの)素直なランタイムで動くとなれば願ったり叶ったり。綺麗にしようとしたとき、括弧省略などのトライアンドエラーはScalaを書いているみたいな感覚でした。で、構文のすべてが式なので、文ではなくひとつの式としてイメージしないとコードの方針が立ちにくいのがOCamlっぽかったですね。このあたりの感覚が浅く広くある人だと、ほんとにすんなりいけそうです。

逆に、何かの偏った方法論に縛られてきた人には、もしかするときついかもしれません。なんだか、新しいプログラム言語はいまこういう次元にあるんだなと思うと、かつてJavaが最新の言語概念リードしていたように、javascriptが再発見されてクロージャブームが世界観を変えたみたいに、いまマルチパラダイムって言ってるものが、なにか名前がついたひとつのパラダイムとして、将来プログラマー必須のスキルになる可能性はなきにしもあらずなんじゃないかと...。