ラムダ式って何なの?

今日の今朝、おもむろにtakeshi.kに絡んでラムダ式について聞いてみた*1
正直、理解するまで魔法にしか見えなかったんだけど・・・。


例えばこれ。

x => x + 1

ぱっと見、意味が分からないんですが。


これの意味は、

x + 1 を x に 入力する

という意味で、〜 => は 〜に入力を意味する。


ただ、後述することを考えると、〜に入力する、というのは誤解を生むかもしれない。MSDNめ・・・。


実際にC#で組むと、

using System;

namespace ConsoleApplication1
{
    class Program
    {
        Func<int, int> Inc = x => x + 1;
        Console.WriteLine("{0}", Inc(3));
    }
}

で、これの結果が

4


まあ、この結果は上の意味をそのまま受け取ればこうなるよね。

なお、Funcは汎用デリゲート*2である。

ラムダ式を使わないデリゲートの場合だとこうなる*3

using System;

namespace ConsoleApplication1
{
    class Program
    {
        Func<int, int> Inc = Increasement;
        Console.WriteLine("{0}", Inc(3));
    }

    public static int Increasement(int x)
    {
        return x + 1;
    }
}


じゃあ、今度はコレ。

(x, y) => x == y


一体、どういうことなの・・・。

左辺の(x, y)はx, yそれぞれに入力する、を意味している。
じゃあ右辺は一体何なのか?

とりあえず次のコードを見よう。

using System;

namespace ConsoleApplication1
{
    class Program
    {
        Func<int, int, bool> Chk = (x, y) => x==y;
        if(Chk(3, 2) == true)
        {
            Console.WriteLine("True");
        } else {
            Console.WriteLine("False");
        }
    }
}

これの結果は、

False

つまり、右辺は入力されたx, yを比較して、bool値を返していることがわかる。


ラムダ式は、型を省略できる場合もあり*4型推論によって、自動的に入力した変数の型が何なのか判断される。


例えば、Customer型が宣言されており、メンバにCityを持つ場合、

customers.Where(c => c.City == "London");

これは、Customer型のみメンバにCityを持つ、という情報から、cは型推論によって、Customer型の変数であることが判断される。


一方、引数がない場合、

() => Something()

とも書ける。


んで、何が利点なのかというと、僕もあまり理解できてはいないのだけれど、デリゲートメソッドを別につくらないでもスマートに書ける、ということだろうか。


ヤバいよオチがつかないよ!もっと熱くなれよ!ラムダ式は分かったけど使いどころがイマイチだよ!


takeshi.k「ラムダ式はそれを活かすライブラリ次第で」


ライブラリ勉強しようぜ。.Net広い。二郎ことtakeshi.kありがとう。

*1:なんで聞いたって?勉強会でも、ちらほらラムダ式の話が出てきてて、何のことかさっぱりわからん、なんてけまらしいんだ。というアレな理由だったりする

*2:Tは引値の型、TResultは返値の型を意味する。デリゲートは関数ポインタみたいなもの。関数を変数みたいに扱うことができ、パラメータとしても代入可能になる。ただポインタ関数と違って実行時の型チェックが厳密

*3:というか、この例だと正直デリゲート使う必要すらない・・・

*4:ただし、デリゲート側での入力値・返値に対応するパラメータは暗黙的に変換できる必要がある。今後、要仕様確認といったところか