curry化と部分適用の違いを自分なりにまとめてみる


関数型プログラミングでおなじみのcurry化。
部分適用と何が違うの? とずーっと悩んできて、やっとなんとか整理がついたような気がするので自分用にまとめみてみます。
言語はjavascriptをチョイスしましたが、言語に特別依存する概念ではありません。

お題: 2つの値を掛け算する関数multiply

var multiply = function(x, y){
    return x * y;
};

console.log(multiply(4, 5));
20

涙が出るくらい簡単ですね。これをcurry化します。

curry化とは、複数引数の関数を1引数の関数の組み合わせ(合成関数)に書き直すことです。
multiply の場合こんな感じになります。

var multiply = function(x){
    return function(y) {
        return x * y;
    }
};

curry化された multiply は 直接的には1引数の関数になりました。更に返り値が(1引数の)関数になっています。
このcurry化された multiple を使用するときには引数を1つずつ渡す必要があります。

console.log(multiply(4)(5));
20

console.log(multiply(4, 5));    // multiple()は1引数の関数になったので、5が無視されていることに注意。
ƒ (y) {
    return x * y;
}

curry化のメリットは?

関数の部分適用(複数引数の関数の一部を固定化して引数を減らした関数を作ること)がしやすくなります。

curry化した multiply では第1引数を 4 に固定(部分適用)して、与えられた値を4倍する multiple4 が簡単につくれます。

var multiply4 = multiply(4);

自分で新しく関数を定義しなくても良いのがポイントです。 multiply は関数を返す関数なんだから当然ですね。

curry化されていない場合に部分適用するには、自分で新しい関数を定義しなければいけません。

var multiply4 = function(y){
    return multiply(4, y);
}

結果はどちらも同じです。

console.log(multiply4(5));
20

関数型プログラミングで currey化が重要なのは?

関数型プログラミングでは関数を組み合わせて目的とする合成関数を作っておいて、そこに値を流し込んで求める結果を得るということを重視します。
unixシェルプログラミングでコマンド(フィルタ)をパイプでつないでパイプラインを作るのと似てますね。

これが可能なのは、各コマンドが1つの標準入力から値を受けて、1つの標準出力に結果を流すというインターフェイスが決まっているからです。
関数型プログラミングも同じで、引数(入力)が複数あると前の関数の戻り値(出力)が受け取りにくくなります。そこで、1引数の関数に分解(curry化)するとインターフェイスが単純になって合成関数が簡単に組めるようになるのです。

まとめ

  • 部分適用とは、複数引数の関数の一部を固定化した関数をつくること。
  • curry化とは、複数引数の関数を1引数の関数に分解すること。
  • curry化すると部分適用が瞬殺で作れるよ。
  • curry化すると関数の合成が簡単になるよ。

…間違いがあったらすまん。