※あってるかどうかといわれるとじしんない
カリー化とか部分適用とかの謎用語
初めてこの単語を見かけたときの「?????」具合がひどかったので自分にわかりやすくまとめてみる。
ネットで調べてみても、結局よくわからないことを書いてるところがあったり、正確だけどとても回りくどい書き方してるところがあったりしてちょっとわかりづらかった。
普通のラムダ式
Func<int, int, int, int> func; // 3つのintを引数にとってintを返す
func = (x, y, z) => x + y + z;
func(10, 20, 30); //-> 60
普通のラムダ式をカリー化したもの
func2 = x => y => z => x + y + z; // この形に変換することをカリー化と呼ぶ
func2(10)(20)(30); // -> 60
かっこを付けてみるとわかりやすいかも
func2 = x => (y => (z => x + y + z)) // intを返す関数、を返す関数、を返す関数
// func2の定義はこんな
Func<int, Func<int, Func<int, int>>> func2; // 書きづらすぎて死ぬ
カリー化した関数をつかう
f1 = func2(10); // f1 の中身は (y => z => 10 + y + z)
f2 = f1(20); // f2 の中身は (z => 10 + 20 + z)
f2(30); // -> 60
一段階ずつ引数を固定した関数を作ることができる。
これは部分適用ではない。
部分適用というのは
func = (x, y, z) => x + y + z;
partial1 = func.ApplyPartially(10) // ApplyPartiallyなんていうメソッドはないけどなんとなくイメージしてくだち
// partial1 の中身は (y, z) => 10 + y + z;
partial1(20, 30) // -> 60
これだけ
こうやってまとめてみたら何が難しくてこれがわからなかったのかわからない……????
1引数の関数がどうのこうのとか難しいこと言う前にコードで示したほうが早かったやつだ!
この記事はあくまでカリー化の概念をつかむためのものであり、__C#でこれをやるメリットは全くないし意味もない!__関数を組み立て、合成できる関数第一なプログラミング言語でやって初めて活きる概念ですね。
ちなみに、C#で普通のラムダ式をカリー化する汎用メソッドとか作ってみようかと思ったけど、引数の数に対してジェネリックなことができないC#でやるのは無茶だった。引数の数毎にコピペで定義すればいけるけど……。あと上で適当にでっち上げたApplyPartiallyも同じように汎用性持たせられなかったのでダメでした。
// 「引数が3つのFunc」に対してカリー化と部分適用をする拡張メソッドは一応こんな感じで実現できます
public static class Extension
{
public static Func<T1, Func<T2, Func<T3, TResult>>> Currying<T1, T2, T3, TResult>(this Func<T1, T2, T3, TResult> func) => x => y => z => func(x, y, z);
public static Func<T2, T3, TResult> ApplyPartially<T1, T2, T3, TResult>(this Func<T1, T2, T3, TResult> func, T1 value) => (x, y) => func(value, x, y);
}