えムナウ Blog

えムナウ の なすがまま

目次

Blog 利用状況

ニュース


follow mnow at http://twitter.com


えムナウのプログラミングのページ

INETAJ

書庫

日記カテゴリ

ギャラリ

ラムダ式について

私がラムダ式を悪夢と表現したのを聞いた方もいるでしょう。
実際使ってみてどこが悪夢なんだと感じられた方も多いでしょう。
便利だからどんどん使っていこうと思っている方もいるでしょう。
でも、一般の人が理解できる範囲内で使ってください。

ちょっと階乗のプログラムを作ってみましょう。
こんな感じですね。

class Fact1

{

    static int f(int x)

    {

        return x == 0 ? 1 : x * f(x - 1);

    }

    public void Factorial()

    {

        for (int i = 1; i < 10; i++)

            Console.WriteLine(f(i));

    }

}

それではラムダ式で各前段階として匿名デリゲートで書いてみましょう。

class Fact2

{

    private Func<int, int> f = null;

    public void Factorial()

    {

        f = delegate(int x)

            {

                return x == 0 ? 1 : x * this.f(x - 1);

            };

        for (int i = 1; i < 10; i++)

            Console.WriteLine(f(i));

    }

}

さて this.f はカッコ悪いですよね。
でもこれは自分を呼ばなきゃいけないので自己言及でどうにもなりません。

delegate(int x)

{

    return x == 0 ? 1 : x * 【ここに名前が書けない】(x - 1);

};

そこで、この deligate を含む deligate を作ります。

Func<Func<int, int>,Func<int, int>> g =

    delegate(Func<int, int> f)

    {

        return delegate(int x)

            {

                return x == 0 ? 1 : x * f(x - 1);

            };

    };

どうやって呼び出せばいいのでしょうか?
g(f)なんて形式では呼び出せません、困ってしまいます。

そんなときに救世主のように寄ってくるのが自己言及の悪魔、不動点演算子(Y Combinator)です。
delegate T Y<T>(Y<T> y); とした瞬間に自分を食って必要なクラスを取り出せてしまいます。
Y(Y)(g) で f が取り出せます。

class Fact3

{

    delegate T Y<T>(Y<T> y);

    public void Factorial()

    {

        Func<Func<int, int>,Func<int, int>> g =

            delegate(Func<int, int> f)

            {

                return delegate(int x)

                {

                    return x == 0 ? 1 : x * f(x - 1);

                };

            };

        Y<Func<Func<Func<int, int>, Func<int, int>>, Func<int, int>>> Y =

            delegate(Y<Func<Func<Func<int, int>, Func<int, int>>, Func<int, int>>> y)

            {

                return delegate(Func<Func<int, int>, Func<int, int>> z)

                {

                    return delegate(int x)

                    {

                        return z(y(y)(z))(x);

                    };

                };

            };

        for (int i = 1; i < 10; i++)

            Console.WriteLine(Y(Y)(g)(i));

    }

}

さて、ラムダ式で書いてみます。
でもお願いですから実験だけの世界にしておいてください。

class Fact4

{

    delegate T Y<T>(Y<T> y);

    public void Factorial()

    {

        Func<Func<int, int>, Func<int, int>> g = f => x => x == 0 ? 1 : x * f(x - 1);

        Y<Func<Func<Func<int, int>, Func<int, int>>, Func<int, int>>> Y = y => f => x => f(y(y)(f))(x);

        for (int i = 1; i < 10; i++)

            Console.WriteLine(Y(Y)(g)(i));

    }

}

幸いなことにラムダ式の左辺に var は使えません。

var g = f => x => x == 0 ? 1 : x * f(x - 1);
var Y = y => f => x => f(y(y)(f))(x);

こんな暗号のような訳のわからない(私だけだと言われそうですが)コードは少なくても見なくて済みそうです。

投稿日時 : 2008年2月17日 22:39

コメントを追加

# re: ラムダ式について 2008/02/17 23:15 えムナウ

Y = y => f => x => f(y(y)(f))(x);
f は紛らわしいですね。Fact3は修正しておいたんですけどね。
Y = y => z => x => z(y(y)(z))(x);

# re: ラムダ式について 2008/02/18 0:50 myugaru

こんばんわー。コメントありがとうございました。
お返しにこういうのを貼っておきますw

http://d.hatena.ne.jp/myugaru/20071208/1197119078
http://d.hatena.ne.jp/myugaru/20071208/1197127169
http://d.hatena.ne.jp/myugaru/20071223/1198339267
http://d.hatena.ne.jp/myugaru/20071224/1198568665
http://d.hatena.ne.jp/myugaru/20071226/1198673852

# re: ラムダ式について 2008/02/18 1:06 えムナウ

>myugaruさん、ありがとうございます。
やっぱりやってみる人いるんですねぇ。
数学の勉強とかならいいんですがね。
実際の仕事でこんなコード見たらいやになります。

#一瞬SPAMコメントだと思ったのは内緒

# re: ラムダ式について 2008/02/18 1:09 myugaru

>実際の仕事でこんなコード見たらいやになります。
同意・・。もちろん私はやってませんよ仕事では^^;

# re: ラムダ式で再帰してみるテスト 2008/09/17 15:55 R.Tanaka.Ichiro's Blog

re: ラムダ式で再帰してみるテスト

タイトル
名前
URL
コメント