読者です 読者をやめる 読者になる 読者になる

プログラミング C# - 翔ソフトウェア (Sho's)

C#/.NET/ソフトウェア開発など

カリー化を C# で説明してみる

今回は、軽めの話題として、関数型プログラミングでお馴染みのカリー化を C# でやってみよう。

■ 関数の作成

先ず、以下のように関数を用意してみる。

// 2つの数の足し算 (引数は2つ)
Func<double, double, double> 足し算 = (x, y) => x + y;

// 2つの数の平均 (引数は2つ)
Func<double, double, double> 平均 = (x, y) => 足し算(x, y) / 2.0;

これらの関数を使ってみると次のようになる。

var 和   = 足し算(1.0, 2.0); // 和の値は 3.0
var 平均値 = 平均(3.0, 4.0); // 平均値は 3.5

■ カリー化

これらは2つの引数を取る関数だ。

このような2つの引数を取る関数は、次のように、1つの引数を取り「1つの引数を取る関数」を返す関数に変換することができる。

Func<double, Func<double, double>> 足し算 = x => (y => x + y);
Func<double, Func<double, double>> 平均 = x => (y => 足し算(x)(y) / 2.0);

このようにして、複数の引数の関数を「1つの引数の関数」で表現することをカリー化という。

カリー化後の関数を使ってみると次のようになる。

var 和 = 足し算(1.0)(2.0); // 和の値は 3.0
var 平均値 = 平均(3.0)(4.0); // 平均値は 3.5

■ 部分適用

カリー化された関数は、引数の一部だけを渡すことで、一部の変数だけが適用された別の関数を作り出すことができる。

これを部分適用と云う。

// 部分適用
Func<double, double> 被加数が1の足し算 = 足し算(1.0);

// 部分適用された関数を使ってみる
var 和 = 被加数が1の足し算(2.0); // 和の値は 3.0

■ 3つ以上の引数の場合の例

3つ以上の引数を取る関数の場合も同様である。

例えば、次のような3つの引数を取る台形の面積を求める関数があってとして、

Func<double, double, double, double> 台形の面積 = (上辺, 下辺, 高さ) => (上辺 + 下辺) * 高さ / 2.0;

// 3つの引数を取る関数を使ってみる
var 面積 = 台形の面積(3.0, 5.0, 2.0); // 面積の値は 8.0

これをカリー化していくと、次のようになる。

Func<double, double, Func<double, double>> 台形の面積 = (上辺, 下辺) => (高さ => (上辺 + 下辺) * 高さ / 2.0);
Func<double, Func<double, Func<double, double>>> 台形の面積 = 上辺 => (下辺 => (高さ => (上辺 + 下辺) * 高さ / 2.0));

つまり、「『関数を返す関数』を返す関数」を返せば良いことになる。

順番に部分適用していくと次のようになる。

Func<double, Func<double, double>> 上辺が3の台形の面積 = 台形の面積(3.0);
Func<double, double> 上辺が3で下辺が5の台形の面積 = 上辺が3の台形の面積(5.0);
var 上辺が3で下辺が5で高さが2の台形の面積 = 上辺が3で下辺が5の台形の面積(2.0);

まとめて書くと次のようになる。

var 面積 = 台形の面積(3.0)(5.0)(2.0); // 面積の値は 8.0