最近、scalaからjavascriptに不本意ながら引っ越してきました。初めは嫌々ながらだったんですけど、ES6になってめっちゃ書きやすくなってるんですね。知りませんでした。
そんなわけで今回は、カリー化の仕組みがjavascriptの標準になさそうだったので、簡単にカリー化したいと思って調べてみると。
結構良さそうなのが、ありました。(
Qiita: JavaScript でカリー化)
そのまま使っても良かったんですけど、僕はjavascriptでは、できるだけthisを使わないようにしているので、リンクの記事のcontextがいらないのと、その場合の空の括弧()がいらないので、上の記事のコードを参考に改造しました。
あと、他の言語から来ると、関数宣言の括弧の中にない引数をargumentsを使って取るのは気持ち悪いので、ES6の可変長引数を使ってこんな風にしてみました。
Function.prototype.curry = function (...args) {
let func = this;
function partial(...args) {
return (args.length >= func.length)
? func.apply(null, args)
: function(...ret_args) {
return partial.apply(null, [...args, ...ret_args]);
}
}
return partial.apply(this, args);
};
とりあえず、こんな感じにして動作確認
function sum1(a, b, c) {
return a + b + c;
}
let sum2 = ((a, b, c) => a + b + c).curry()
console.log(sum1.curry(4, 5, 6)) // <- 6
console.log(sum1.curry(4)(5)(6)) // <- 15
console.log(sum2(10)(11)(12)) // <- 33
これでいいんだけど、あまりビルトインのprototypeを勝手に拡張すんな!としつこくMDN(
ココや
ココ)に書いてあるので、僕は潔癖でないのでそういうの嫌なんだけど、まあ後でcurryメソッドとか正式に追加されたらそれはそれで嫌なので、ただの関数版も作ってみた。
scalaのimplicit conversionが懐かしいぜ・・・
function curry(fn) {
return function partial(...args) {
return (args.length >= fn.length)
? fn.apply(null, args)
: function(...ret_args) {
return partial.apply(null, [...args, ...ret_args]);
}
}
};
こっちの使い方はこんな感じ
let sum3 = curry((a, b, c) => a + b + c)
// sum1は、上のを使いまわし
console.log(curry(sum1)(4, 5)(6)) // <- 15
console.log(curry(sum1)(1)(2)(3)) // <- 6
console.log(sum3(20)(21)(22)) // <- 63
console.log(sum3(2)(4, 6)) // <- 12
まあ、難しいこと考えなければこれで良いような気がします。
関数版は、憎たらしいthisも使わないですんでるし。
昔、10年くらい前には、
{javascriptって何でもfunctionで出来てて意味わかんねー}
とかって思ってたんすけど、その基本設計と最近のES5,ES6と続く言語の拡張により俄然、モダンな書き方ができる言語に変化してきてるんですね。