C#でカリー化
- 2009-03-15
LINQハァハァ→関数型言語?→Haskell!という感じに辿ってHaskellを勉強中なので、カリー化について。Haskell、の前にまずはC#で考える。例えば、たまーに見かける「a => b => c => a + b + c」のようなものがパッと見意味分からない。Haskellでも型定義Int->Int->Intみたいことやるので、それと同じなわけっぽいですけれど。
ゆっくり分解すると、「=>」の左が引数、右が戻り値なのでa =>( b => c => a + b + c) つまり Func<int,???>。???の部分もカッコでくくって b =>( c => a + b + c) つまりFunc<int,Func<int,???>>。c=>a+b+cは、見たまんまなのでFunc<int,Func<int,Func<int,int>>>ということになる。
冷静に解きほぐせばそんな難しくない。というわけで準備運動が済んだので、カリー化関数を作ろう。
// カリー化する関数
static Func<T, Func<U, V>> Currying<T, U, V>(Func<T, U, V> func)
{
return t => u => func(t, u);
}
// 非カリー化する関数
static Func<T, U, V> UnCurrying<T, U, V>(Func<T, Func<U, V>> func)
{
return (t, u) => func(t)(u);
}
// 例として使うx+yを返す関数
static int Sum(int x, int y)
{
return x + y;
}
static void Main()
{
int num1 = Sum(3, 5); // 普通に、8
// Sumをカリー化する、関数はデリゲートに包む必要がある
var CurriedSum = Currying((Func<int, int, int>)Sum);
int num2 = CurriedSum(3)(5); // 当然、8
var BindedSum = CurriedSum(3); // 3を部分適用する
int num3 = BindedSum(5); // 勿論、8
var UnCurriedSum = UnCurrying(CurriedSum); // 非カリー化
int num4 = UnCurriedSum(3, 5); // 当然、Sum関数と一緒
}
多分、あってる、と思いたい。カリー化とは大雑把に言って「f(x,y) = g(x)(y)」ということのようなので、そうなるようバラしたり戻したり。そういえばで気付いたのですが、関数/ラムダ式をデリゲートに包む方法は
Func<int> test1 = () => 1;
var test2 = (Func<int>)(() => 2);
var test3 = new Func<int>(() => 3);
意外とバリエーションがある、気がする。ようは省略出来るだけでしょって話っぽいけど。単独で定義するときは1番を用いるかなー。癖でとりあえずvar、って書いてから、あー、これはnewするのダルいケースだった、varじゃなくてちゃんと書かなきゃ、と後ろに戻ったりするのがよくあって笑えない。
クロージャ
関数を返す関数繋がりでついでに、関数型言語って何がすごいんですか - Gemmaの日記からロケットのコードのC#版を。
static void Main()
{
Func<int, Action> Rocket = n => () => Console.WriteLine((n > 0) ? (n--).ToString() : "liftoff");
var F = Rocket(3);
var G = Rocket(3);
F(); F(); F(); F(); // 行数使うのもアレなので横に並べます
G(); G();
}
中々なスッキリ具合。function retrunが必要ない、というのがC#ラムダ式の強みですねえ。JavaScriptは(IEのせいもあって)function{return}が必須なのがカッタルイ。そんなことを思うと、C#はとても身軽で、個人的にはある意味とてもLightweightだと感じてしまったりする。
インテリセンスがりがり、コードスニペットがりがり、コードフォーマッタがりがりな上に乗っかっているので、軽快というか、Lightweight Languageが短距離走選手のようだとしたら、VS2008+C#は重武装+ロケットブースターで、それ自体は鈍重であっても、結果的にブースター付きのは強烈なスピードだよね、みたいな。軽快に書き進められるの自分の力じゃなくてVisualStudioの力でしょ、と思わないときもないけれど。