Scheme手習い(17) Yコンビネータ(2)
define
なしで再帰を実現できたものの、わかった感が薄くて今ひとつ
eternity
の唐突感(mk-length mk-length)
の手品感
このあたりを解決しないと眠れそうにありません
いえ寝ます
いえ自分なりに納得感のある道を探してみます
厳密さよりも感覚的に納得できるような方向で
まずはlength
からスタート
define
を使わずに同じことを書けたら勝ち
(define length
(lambda (l)
(cond ((null? l) 0)
(else (add1 (length (cdr l)))))))
defineが使えないので取ります
(lambda (l)
(cond ((null? l) 0)
(else (add1 (length (cdr l))))))
self
という名前を入れておきます
(lambda (l)
(cond ((null? l) 0)
(else (add1 (self (cdr l))))))
このままではself
が定義されてないよと怒られてしまうので、lambda
の仮引数にしてしまいましょう
(lambda (self)
(lambda (l)
(cond ((null? l) 0)
(else (add1 (self (cdr l)))))))
これで一応ちゃんとした関数になりました
あとはself
に元の関数を入れてやれば再帰するんじゃ?
正確には自分自身じゃないけど、同じコードならいいよね?
同一人物じゃないけど双子の弟みたいな
((lambda (self)
(lambda (l)
(cond ((null? l) 0)
(else (add1 (self (cdr l)))))))
(lambda (l)
(cond ((null? l) 0)
(else (add1 (self (cdr l)))))))
ほらほらほら
もうできちゃったんじゃないの?
> (((lambda (self)
(lambda (l)
(cond ((null? l) 0)
(else (add1 (self (cdr l)))))))
(lambda (l)
(cond ((null? l) 0)
(else (add1 (self (cdr l)))))))
'(1 2 3))
self: undefined;
あーそうですねー外側のself
は定義されてないですねー
馬鹿ですねー
外側のself
がエラーにならないようにするにはどうすればいいでしょう?
じー
そうか、外側の関数も引数でself
自身を受け取るようにすればいいですね!
こう
((lambda (self)
(lambda (l)
(cond ((null? l) 0)
(else (add1 (self (cdr l)))))))
(lambda (self)
(lambda (l)
(cond ((null? l) 0)
(else (add1 (self (cdr l))))))))
おっといけない
このself
は自分自身を引数に取って、つまり(self self)
となって初めて
さっきまでのself
になるのでいじってやらないと
((lambda (self)
(lambda (l)
(cond ((null? l) 0)
(else (add1 ((self self) (cdr l)))))))
(lambda (self)
(lambda (l)
(cond ((null? l) 0)
(else (add1 ((self self) (cdr l))))))))
これでもう動かない理由はないはず
> (((lambda (self)
(lambda (l)
(cond ((null? l) 0)
(else (add1 ((self self) (cdr l)))))))
(lambda (self)
(lambda (l)
(cond ((null? l) 0)
(else (add1 ((self self) (cdr l))))))))
'(1 2 3))
3
動きました
(lambda (self) ...)
が2箇所あります
これはself
自身なのでself
と名前をつけましょう
((lambda (self)
(self self))
(lambda (self)
(lambda (l)
(cond ((null? l) 0)
(else (add1 ((self self) (cdr l))))))))
できましたね
> (((lambda (self)
(self self))
(lambda (self)
(lambda (l)
(cond ((null? l) 0)
(else (add1 ((self self) (cdr l))))))))
'(1 2 3))
3
(self self)
が(self self)
を呼び続ける、ってことですね
self
がself
自身を呼び出せればいいんだけど
self
はself
自身のことを知らないからself
を渡してやる、と
いったところでしょうか
あれこれ考えてるうちにこの関数も普通に再帰に見えてきましたよ