よーしパパ、関数に名前を付けずに再帰させちゃうぞぉ!(その3)
続き。
length0_3とlength1_3とlength2_3に書き換えることで、結構コードも簡潔になった。
しかし、まだ「名前を付けずに再帰」という目標にはたどり着いてない。
なんとかせんとねー。
- L
再帰ってどんなんよ?
- R
mk-lengthを任意の関数へ無限に適用するみたいな感じやな。
- L
ほんまに無限回適用せなあかんの?
- R
んなあほな。
length(←いま作ろうとしている関数)を使うときはいつでも有限回の繰り返しでええよ。
せやけど、何回かはわからん。
- L
なんぼmk-lengthが必要やったか想像できた?
ここら辺までは意味がつかめた。あとはサッパリ。(これは英語の問題。
ということで英語は早々にあきらめ、とりあえずソースコードを写経。
"Then is this still length0"って書いてあるから、たぶんlength0_*と同じ意味の関数なんだろう。
length0_4という名前にした。
(define length0_4 ((lambda (mk-length) (mk-length mk-length)) (lambda (length) (lambda (l) (cond ((null? l) 0) (else (+ 1 (length (cdr l)))))))))
とな。んで、Gaucheで評価してみる。
gosh> (length0_4 '()) 0
まぁ、当然か。
んで、次が大事。空っぽじゃないリストを食わせてみるとどうなるのか実験。
gosh> (length0_4 '(hoge)) *** ERROR: operation + is not defined between 1 and #<closure (#f #f)>
とな。
「整数1と関数の間には+演算が定義されてないYO!!」って怒ってるっぽい。
eternityのときは「評価が終了しない」だったけど、mk-lengthに変えてから「エラーで止まる」という挙動に変わった。
ええのか?これで?
どこでエラーになってるのか調べてみよう。
...って、察しはつくけどね。eternityだった所のmk-lengthが関係してるんだろうな。たぶん。
orz
(mk-length mk-length)
みたいな、自分自身を引数にするとか意味わからんし。
このままじゃ自分の頭じゃ理解できなさそうなので、lambdaをなくしていく方向で変形していってみる。
とりあえず、
(lambda (length) ...
を適当にfと置いてみる。したらば、
((lambda (mk-length) (mk-length mk-length)) f)
ってできる。さらにfを引数に、関数適用すると
(f f)
さらにfを展開すると、
((lambda (length) (lambda (l) (cond ((null? l) 0) (else (+ 1 (length (cdr l))))))) (lambda (length) (lambda (l) (cond ((null? l) 0) (else (+ 1 (length (cdr l))))))))
となる。なんか、どっかで見たことある形やな。
length0_2(id:yagiey:20080324)のeternityがlambda式に置きかわっとる感じだ。
...って、あたりまえか。
length0_3のeternityをmk-lengthに置換したからなぁ。
ということは、length0_2のeternityの部分をfで置き換えて書き直していくと、最終的にはlength0_4は
(lambda (l) (cond ((null? l) 0) (else (+ 1 ((lambda (length) (lambda (l) (cond ((null? l) 0) (else (+ 1 (length (cdr l))))))) (cdr l)))))
となるはずやな。これやと、何処が何故エラーになるかすぐ分かる。
lengthは「1つ関数を引数として取る関数を返す関数」やもん。
(length (cdr l))
の部分は何らかの関数に評価される。
だから「数値の1と関数の間に+演算が定義されていない」というエラーなわけやな。
あー、横道にそれてばっかりで、なかなか進まん!
これだけグダグダ書いて1ページ分も進んでないし...。
ってか、未だにlambdaに慣れていない感じが否めない。
(ノ∀`)タハー