Twitterでちょっと前に話題になっていたカリー化の話題について。
まずは議論を始めるにあたっての基本である言葉の定義、つまりカリー化の定義についてあきらかにしておきたい。
言語間でカリー化の定義が異なる場合があるかもしれないが、JavaScriptでは一般的には以下のようなコードがカリー化と呼ばれることが多いと思う。
const hoge = a => b => a + b;
// シンタックスシュガー
// const hoge = ( a, b ) => { a + b };
ようは引数をひとつずつとって関数を返し、それを繰り返すことで関数が繋がっているようにすることをカリー化と呼んでいる(と私は認識している)。
厳密にいうと、複数の引数を取る関数をロジックのベースとして、引数が「元の関数の最初の引数」で、戻り値が「元の関数の残りの引数を取り、結果を返す関数」となる関数である。
「f(x,y) = g(x)(y)」が常に成立する場合、gがfのカリー化であるという。
JavaScriptの文法に慣れていない人であれば、とても不思議なコードに見えるだろう。
JavaScriptでは関数は第一級オブジェクトなので、関数を引数として渡すことができ、高階関数(関数を引数または戻り値とする関数)を実現することができる。
ちなみにカリー化と似た概念としてデコレータ関数と部分適用というものがある。
デコレータ関数は、関数の中身を入れ替えずに処理を追加することである。
const decorator = func => {
return () => {
console.log( 1 );
func.apply( this, arguments );
};
};
let decorated = () => {
console.log( 2 );
};
decorated = decorator( decorated );
decorated(); // 1 2
また部分適用は任意の引数を固定した別の関数を作成することである。
const foo = hoge(1);
console.log( foo(2) );
固定と言ってもリテラルを使うという意味ではなく、抽象化された変数を使用するのがほとんどだ。
カリー化は関数型プログラミングの概念であり、数学者のHaskell Curry氏の名前に由来する。
関数型プログラミングでは関数は呼び出すものではなく、適用されるものとして説明されるように、カリー化は各々の引数が部分的に適用されることによって関数を変換させる処理と考えられる。
つまり、カリー化はその処理全体(関数がひとつずつ繋がれていること)を指し、部分適用はそのプロセスにおけるひとつの関数の処理を指す(と私は認識している)。
次にカリー化を使用することについて、一般的には同じ関数をほとんど同じパラメーターで呼び出している場合は考慮すべきとされる。
JavaScriptにおいてはある種の視認性の観点で採用されることもあるが、プログラミングの本質としては、わかりやすさとパフォーマンスのふたつの観点でロジックを考慮すべきであると考えている。
今回はパフォーマンスについてはいくらでも想像を働かせることができることから考慮しないとし、わかりやすさについては変動的あり、OSSではなく社内開発のようなので一般論は切り離して考えるべきであり、当該環境内での素養を鑑みたうえでロジックを決定すべきであると考える。
そのため多くの方が言及されているように、その環境内でわかりづらいと判断されるのであればロジックの採用を見送るべきであると私は考えている。
ただし、これはコードの側面だ。
たとえばロジックの採用に社内の人材の啓蒙的な意味を込めていた場合、これは将来的な財産となりうる。
もちろんそれがうまくいかなければ、(社内案件でない場合)納品先のクライアントにはたまったものではないが、この可能性も捨てきれない。
あるいは当人がカリー化を覚えたてで使ってみたかった場合は当人の成長の礎になるだろう。
ただし適切な倫理観があれば個人制作以外ではそのようなことをしないだろうし、SNSでは批判されるだろう。
今回批判している人のなかにはこれを察したから、強く当たっているような気がしないでもない。
もちろんプログラマーである以上は、コードのことだけ考えるべきである。
ただし、いずれにしても論理がすべてではない世の中なので、感情に寄り添うことも大事だろう。
そして双方SNSで発信する意味についても考慮すべきだと感じたXトレンドだった。