今更カリー化

自分のメモ用のWikiに書いてあるJavaScriptのカリー化の説明が単なる部分適用だったり間違いが多いのに気付いたので書き直していたのだけど、その時、ふと汎用的なカリー化処理を実装できないかな?と思って色々試してみたのだが、なかなか上手くいかないのでググってみたらdankogai無双。

404 Blog Not Found:javascript - 弾もcurryを煮込んでみた

ストレートにfunctionをネストしたコードを生成して、Functionコンストラクタの引数に渡せばevalも要らないという…。このアプローチにさらっと気付ける辺りが地頭のよさなんだろうなスゲーと思ったよ。

JavaScriptの関数はオブジェクトなんだから、どうせならFunctionのメソッドにしてしまおうぜ

Function.prototype.curry = function(){
  var fs      = this.toString();
  var op      = fs.indexOf('(');
  var cp      = fs.indexOf(')');
  var ob      = fs.indexOf('{');
  var cb      = fs.lastIndexOf('}');
  var args    = fs.substr(op+1,cp-op-1).split(/,\s*/);
  if (!args.length) return this;
  var curried = new Function(args.pop(), fs.substr(ob+1,cb-ob-1));
  while (args.length){
    curried = new Function(args.pop(), 'return ' + curried.toString().replace(/\n/,''));
  }
  // 引数が与えられていたら適用しておく
  if (arguments.length) {
    return curried(arguments[0]);     
  } 
  return curried;
};

function sum(a,b,c,d) {
  return a + b + c + d;
}

console.log(sum.curry().toString());
console.log(sum.curry(1)(2)(3)(4));

Firebugsのコンソールで叩いてみると

function anonymous(a) { return function anonymous(b) {return function anonymous(c) {return function anonymous(d) {return a + b + c + d;};};}; }

10

ステキな感じ