# Y Combinatorを直感的に理解。しようと試みる。 _published: 2008/02/02_ ![alt](http://b.hatena.ne.jp/entry/image/http://d.hatena.ne.jp/shunsuk/20080202/1201938663) [id:yuji1982](http://d.hatena.ne.jp/yuji1982/)さんのエントリ。 - [Y Combinatorが凄すぎる! - yuji1982の日記](http://d.hatena.ne.jp/yuji1982/20080124/1201177935) なにこれ。Y Combinatorすげぇ!意味わからん。 今朝、妻からメールが来ました。 > 静かに歩く犬は犬じゃない。私の夢に出てきたフレーズ。 意味わからん。でも、それ以上にY Combinator意味わからん。 普通にフィボナッチ数を計算するプログラムは、こうですよね。 ```cs static int fib(int n) { if (n < 2) { return n; } else { return fib(n - 1) + fib(n - 2); } } ``` これを、C#のクエリ式で書くと。 ```cs static int fib(int num) { Func<int, int> f = null; f = n => (n < 2) ? n : f(n - 1) + f(n - 2); return f(num); } ``` `if` は三項演算子に変えておきました。そのほうがカッコイイから。 で、`Func<int, int> f = null;` っていらないよね。って話しです。そこで、id:yuji1982さんのところのメソッドをパクってきました。このメソッドが噂のY Combinatorらしいです。 ```cs static Func<T, T> Fix<T>(Func<Func<T, T>, Func<T, T>> F) static Func<T, T> Fix<T>(Func<Func<T, T>, Func<T, T>> F) { return t => F(Fix(F))(t); } ``` この魔法のメソッドを使うと、 `fib` メソッドはこう書けます。 ```cs static int fib(int num) static int fib(int num) { return Fix<int>(ff => n => (n < 2) ? n : ff(n - 1) + ff(n - 2))(num); } ``` なにこれ。Y Combinatorすげぇ!意味わからん。 そこで、可哀想な私が、頑張って仕組みを考えてみます。 まずは、ラムダ式だと型が省略されるので、匿名メソッドに書き換えます。それから、変数名をわかりやすく日本語に。.NETは日本語OKなので、下のコードはコンパイル可能です。Tは、intに固定しました。 ```cs static Func<int, int> Fix(Func<Func<int, int>, Func<int, int>> 擬似フィボ使って元のフィボ返す) { // 「擬似フィボ使って元のフィボ返す」から「元のフィボ」を取り出して実行する関数 Func<int, int> 最終フィボ = delegate(int num) { // 「擬似フィボ」と「最終フィボ」は同じ(ただし、階層が違うイメージ) Func<int, int> 擬似フィボ = Fix(擬似フィボ使って元のフィボ返す); // 「元のフィボ」を取り出す Func<int, int> 元のフィボ = 擬似フィボ使って元のフィボ返す(擬似フィボ); // 「元のフィボ」を実行 int 答え = 元のフィボ(num); return 答え; }; return 最終フィボ; } static int fib(int num) { // 「擬似フィボ」を入れたら「元のフィボ」を返す関数 Func<Func<int, int>, Func<int, int>> 擬似フィボ使って元のフィボ返す = delegate(Func<int, int> 擬似フィボ) { Func<int, int> 元のフィボ = n => (n < 2) ? n : 擬似フィボ(n - 1) + 擬似フィボ(n - 2); return 元のフィボ; }; Func<int, int> 最終フィボ = Fix(擬似フィボ使って元のフィボ返す); return 最終フィボ(num); } ``` そして、このコードをグルグル眺めます。グルグル。グルグル。グルグル!そういえば、再帰でした! 「最終フィボ」と「擬似フィボ」が同一人物だというのがポイントですね。この「最終フィボ=擬似フィボ」がひとつの「環境」になっています。図を描くと、こんなカンジ。 ![[20080202164458.png]] 「元のフィボ」から「最終フィボ=擬似フィボ」を呼んでいますが、これは「元フィボ」が所属する「最終フィボ=擬似フィボ」ではなくて、ひとつ下の階層の「最終フィボ=擬似フィボ」を呼んでいるイメージです。図を描くと、こんなカンジ。 ![[20080202164550.png]] おお、何となく解ったような。今日はこれくらいにしといてやろう。 それでは、Y Combinatorをググって見ましょう。順番が逆か。 [id:amachang](http://d.hatena.ne.jp/amachang/)のエントリ。 - [Y コンビネータって何? - IT戦記](http://d.hatena.ne.jp/amachang/20080124/1201199469) ~~さすが。~~それにしても、JavaScriptすげぇ。(追記:id:amachangに対して「さすが」のひと言で済ますのは失礼ですよね。裏でがむしゃらにやってるんだから。) しかし、「式がすべて λ 計算に変換できる」という考え方が具体的にどのように役にたつかが分からない>< コードが破壊的じゃなくなる。ってことでしょうか。状態を持たない。スレッドセーフ。これからはマルチコアの時代。マルチスレッドは当たり前。.NETはスレッド生成するごとに、自動的にCPUに割り当ててくれるから楽チン。サーバーサイドだけでなく、クライアントもマルチコア。ちなみに、Windows Formsのイベントは「シングルスレッド・マルチ・アパートメント・モデル」で、マルチスレッドじゃありません。当たり前か。クライアントからサーバーを呼び出すときに、非同期で呼び出すことが増えるでしょうね。と、マルチスレッドの話しにもって行きましたが、関係あるのかどうかは不明です。たぶん、関係ないです。そんなこと言っている人、誰もいないし。そういえば、SOA(サービス指向アーキテクチャ)は、オブジェクト指向と違って状態(ステート)を持ちません。そうすると、オブジェクト指向言語より関数型言語ってことですか?だからF#とか? id:amachangのエントリをブクマしてる人は、解ってる人と、まったく解ってない人に二極化してますね。 こういう計算の話だと、dankogai氏も何か言ってるのではないでしょうか。と思ったら、案の定ありました。 - [404 Blog Not Found:TuringとChurchの狭間で](http://blog.livedoor.jp/dankogai/archives/50458503.html) あとで読む。今日はK-1を観ないといけないので。 Schemeで。 - [Y Combinator](http://www.loveruby.net/ja/misc/ycombinator.html) あとで読む。今日はK-1を観ないといけないので。 その他もまとめようと思ったら、d:yuji1982さんのブックマークにまとまってるじゃないですか。 - [はてなブックマーク - yuji1982のブックマーク - Y combinator](http://b.hatena.ne.jp/yuji1982/Y%20combinator/) あと、このエントリがおもしろいかも。理解していませんが。 - [ホワット・ア・ワンダフル・ワールド 2 つの原理と文化](http://alohakun.blog7.fc2.com/blog-entry-894.html) ラムダ計算とかチューリングマシンとか。そういえば書店で「たのしいRuby」のナナメ向かいの書棚にそんな本が並んでました。今までスルーしてきましたが、これはおもしろそう。勉強してみよう。