■Y-Combinator
「Y-Combinator」を理解するために書いたコードを元に、思考の過程を書く。
■参考
記事最下に記載。
■材料
再帰を伴う処理を基に書いていく。
通例通り階乗(http://ja.wikipedia.org/wiki/階乗)を求める「fact」関数を例に取る。
■その前に・・・
Y-Combinatorは何がしたいのか?
・無名(匿名)関数で再帰を行いたい。
⇒ 普通は「fact」関数の定義の中で「fact」呼び出しが行われる。
⇒ 「fact」という名前を使わずに再帰したい。
■注
1)、「;」で始まるコメントは出鱈目な英語です。(DrScheme(http://www.db.is.kyushu-u.ac.jp/enshu/)の日本語表示が気持ち悪いから)
2)、「;=>」は実行結果の出力
まずは与えられた数字の階乗を求める関数、「fact」を定義してみる。
;normal fact (define fact (lambda (n) (if (zero? n) 1 (* n (fact (- n 1)))))) (fact 5) ;=> 120 |
;gate of normal fact (define fact-maker (lambda () (lambda (n) (if (zero? n) 1 (* n (fact (- n 1))))))) ((fact-maker) 5);=> 120 |
;receive fact (define fact-maker (lambda (f) (lambda (n) (if (zero? n) 1 (* n (f (- n 1))))))) ((fact-maker fact) 5);=> 120 |
(if (zero? n)
1
(* n (f (- n 1))))
;maker receive maker (define m (lambda (f) (lambda (n) (if (zero? n) 1 (* n ((f f) (- n 1))))))) ((m m) 5);=>120 |
ついでに「fact-maker」を「m」に置き換える(見づらかったので)。
fact-makerはfactを置き換えるためのものなので当然正常に動く。ただし、fact-makerはfactを引数に取っていた。置き換えると、fact-makerはfact-makerを引数に取らなければならない。
よって、fact-makerに渡されたfact-makerは引数fに割り当てられることになる。つまり、(f (- n 1))は((f f) (- n 1))となる。 ((fact-maker fact-maker) (- n 1)) ⇒ ((f f) (- n 1))
((m (lambda (f) (lambda (n) (if (zero? n) 1 (* n ((f f) (- n 1))))))) 5);=>120 |
(((lambda (f) (lambda (n) (if (zero? n) 1 (* n ((f f) (- n 1)))))) (lambda (f) (lambda (n) (if (zero? n) 1 (* n ((f f) (- n 1))))))) 5);=>120 |
; (f 5) equals ((lambda (n) (f n)) 5) ; ((lambda (n) ((f f) n)) 5) (define m (lambda (f) (lambda (n) (if (zero? n) 1 (* n ((lambda (n) ((f f) n)) (- n 1))))))) ((m m) 5);=>120 |
(【scheme】schemeのlambdaラムダλ(http://ameblo.jp/valvallow/entry-10182420367.html)を見ればわかるように(わかりにくすぎる))
(define m (lambda (f) (lambda (n) (if (zero? n) 1 (* n (f (- n 1))))))) |
((m m) 5) |
((m (lambda (n) ((f f) n))) 5);=> error |
;gate of y-combinator (lambda (p) (m (lambda (n) ((p p) n)))) |
((m (lambda (p) (m (lambda (n) ((p p) n))))) 5);=> 120 |
(((lambda (p) (m (lambda (n) ((p p) n)))) (lambda (p) (m (lambda (n) ((p p) n))))) 5);=> 120 |
;receive m receive 5 (((lambda (f) ((lambda (p) (m (lambda (n) ((p p) n)))) (lambda (p) (m (lambda (n) ((p p) n)))))) m) 5) |
;replace m to received f ;this is the y-combinator (lambda (f) ((lambda (p) (f (lambda (n) ((p p) n)))) (lambda (p) (f (lambda (n) ((p p) n)))))) |
;receive 5 reveive m to execute y-combinator (((lambda (f) ((lambda (p) (f (lambda (n) ((p p) n)))) (lambda (p) (f (lambda (n) ((p p) n)))))) m) 5);=>120 |
;named Y to y-combinator (define Y (lambda (f) ((lambda (p) (f (lambda (n) ((p p) n)))) (lambda (p) (f (lambda (n) ((p p) n))))))) |
((Y m) 5);=>120 ((Y m) 10);=>3628800 |
;twice ;(lambda (p) ; (f (lambda (n) ((p p) n)))) ; to once (define Y (lambda (f) ((lambda (h)(h h)) (lambda (p) (f (lambda (n)((p p) n))))))) ((Y m) 5);=> 120 |
;fibonacci (define fib (lambda (n) (if (<= n 2) 1 (+ (fib (- n 1))(fib (- n 2)))))) (fib 10);=> 55 |
;Y-Combinator fibonacci (define fib (lambda (f) (lambda (n) (if (<= n 2) 1 (+ (f (- n 1))(f (- n 2))))))) ((Y fib) 10);=> 55 |
【全景】
;normal fact (define fact (lambda (n) (if (zero? n) 1 (* n (fact (- n 1)))))) (fact 5) ;=> 120 ;gate of normal fact (define fact-maker (lambda () (lambda (n) (if (zero? n) 1 (* n (fact (- n 1))))))) ((fact-maker) 5) ;receive fact (define fact-maker2 (lambda (f) (lambda (n) (if (zero? n) 1 (* n (f (- n 1))))))) ((fact-maker2 fact) 5) ;maker receive maker (define m (lambda (f) (lambda (n) (if (zero? n) 1 (* n ((f f) (- n 1))))))) ((m m) 5) ((m (lambda (f) (lambda (n) (if (zero? n) 1 (* n ((f f) (- n 1))))))) 5) (((lambda (f) (lambda (n) (if (zero? n) 1 (* n ((f f) (- n 1)))))) (lambda (f) (lambda (n) (if (zero? n) 1 (* n ((f f) (- n 1))))))) 5) ; (f 5) equals ((lambda (n) (f n)) 5) ; ((lambda (n) ((f f) n)) 5) (define m2 (lambda (f) (lambda (n) (if (zero? n) 1 (* n ((lambda (n) ((f f) n)) (- n 1))))))) ((m2 m2) 5) ;(lambda (f) ; (f0 (lambda (n) ((f f) n)))) ; is one of fact-maker (define f0 (lambda (f) (lambda (n) (if (zero? n) 1 (* n (f (- n 1))))))) ;gate of y-combinator (lambda (p) (f0 (lambda (n) ((p p) n)))) ((m (lambda (p) (f0 (lambda (n) ((p p) n))))) 5) (((lambda (p) (f0 (lambda (n) ((p p) n)))) (lambda (p) (f0 (lambda (n) ((p p) n))))) 5) ;receive f0 receive 5 (((lambda (f) ((lambda (p) (f0 (lambda (n) ((p p) n)))) (lambda (p) (f0 (lambda (n) ((p p) n)))))) f0) 5) ;replace f0 to received f ;this is the y-combinator (lambda (f) ((lambda (p) (f (lambda (n) ((p p) n)))) (lambda (p) (f (lambda (n) ((p p) n)))))) ;receive 5 reveive f0 to execute y-combinator (((lambda (f) ((lambda (p) (f (lambda (n) ((p p) n)))) (lambda (p) (f (lambda (n) ((p p) n)))))) f0) 5) ;named Y to y-combinator (define Y (lambda (f) ((lambda (p) (f (lambda (n) ((p p) n)))) (lambda (p) (f (lambda (n) ((p p) n))))))) ((Y f0) 5) ((Y f0) 10) ;twice ;(lambda (p) ; (f (lambda (n) ((p p) n)))) ; to once (define Y2 (lambda (f) ((lambda (h)(h h)) (lambda (p) (f (lambda (n)((p p) n))))))) ((Y2 f0) 5) ;fibonacci (define fib (lambda (n) (if (<= n 2) 1 (+ (fib (- n 1))(fib (- n 2)))))) (fib 10) ;Y-Combinator fibonacci (define fib2 (lambda (f) (lambda (n) (if (<= n 2) 1 (+ (f (- n 1))(f (- n 2))))))) ((Y fib2) 10) |
Yコンビネータはすごい。
何がすごいか、言語化できない。
ということは、まだ理解できていない。ということ。
求め方、組み方はなんとなく理解できた。
他の言語でも組める気はする。
JavaScript、Ruby、C#で試してみたい。
Yコンビネータの何がすごいのか、言語化できるように理解を深めたい。
Schemeの勉強になったし、Y-Combinatorの求め方もわかったし、遅延評価についてはまだイメージがぼやけってるけど、少しだけ想像できるようになってラッキー♪
なにより、すごくおもしろかったw
【参考】
[C#]Y Combinatorが凄すぎる!
http://d.hatena.ne.jp/yuji1982/20080124/1201177935
⇒ 発端の記事。
ちょうどyuji1982さんとTwitterなんかで話すようになったころ。
2008年の1月くらいにこの記事見て、yuji1982さんが遠い世界の人だと感じた。
Y コンビネータって何? - IT戦記
http://d.hatena.ne.jp/amachang/20080124/1201199469
⇒ もう一つの発端。
世間はこれで火がついたっぽい。
yuji1982のブックマーク / Y combinator (11)
http://b.hatena.ne.jp/yuji1982/Y%20combinator/
⇒ 発端となったyuji1982さんのYコンビネータに関するブックマーク。
Y Combinator
http://www.loveruby.net/ja/misc/ycombinator.html
⇒ 今回は主にここを参考にした。
Scheme
Yコンビネータを読み解こう
http://d.hatena.ne.jp/tanakaBox/20080203/1202023473
⇒ 後で知ったページ。ここが一番わかりやすい。
Scheme
Y combinator on Scheme
http://fixedpoint.jp/2007/02/14/y.html
⇒ Scheme
不動点演算子ふたたび
http://d.hatena.ne.jp/sumii/20051203/1133575324
⇒ Scheme
C# 3.0 と不動点演算子
http://d.hatena.ne.jp/NyaRuRu/20070722#1
⇒ C#
以前から思ってたけど、異世界の人。
Yコンビネータができるまで(C#)
http://faroffsea.blogspot.com/2008/09/yc.html
⇒ C#
C#でYコンビネータ
http://blog.inomata.lolipop.jp/?eid=815474
⇒ C#
Recursive lambda expressions
http://blogs.msdn.com/madst/archive/2007/05/11/recursive-lambda-expressions.aspx
⇒ C#
不動点オペレータについて
http://www.ice.nuie.nagoya-u.ac.jp/~h003149b/lang/fix.html
⇒ Scheme
ホワット・ア・ワンダフル・ワールド
http://alohakun.blog7.fc2.com/blog-entry-894.html
⇒ 直接は関係ない。
そろそろ分かっておきたいY Combinator
http://d.hatena.ne.jp/authorNari/20081130/1227977113
⇒ Ruby
Yコンビネータメモ
http://d.hatena.ne.jp/gotin/20080127/1201372491
⇒ JavaScript
Yコンビネータ復習
http://faroffsea.blogspot.com/2008/02/y.html
⇒ Common Lisp
MIT(マサチューセッツ工科大学)の盾
http://groups.csail.mit.edu/mac/projects/scheme/
⇒ SICPはここの教科書らしい。
0 件のコメント:
コメントを投稿