Scheme で append 手続きを再実装(復習)
Scheme で append 手続きを再実装(完成) - satosystemsの日記で、コメントで教えてもらった append の実装を解析。
(define append (lambda args (let f ((ls '()) (args args)) (if (null? args) ls (let g ((ls ls)) (if (null? ls) (f (car args) (cdr args)) (cons (car ls) (g (cdr ls)))))))))
たった 9 行のコードなのに、スラスラ頭に入ってこない。Java に直そうと思ったけど、それすらできなかった。
このコードで勉強になったことをまとめておこう。
学んだこと1
僕の理解だと、可変長引数は (x . y) のような書き方をしなきゃいけないはずなんだけど、なんでこの手続きはひとつしか書かれていないのか。
display で見てみたら理解できた。
(append '(a b) '(c d)) という呼出しだと args は ((a b) (c d)) になる。なるほど、これを知っていれば、別のロジックで組んでいたなぁ。見返してみたら R5RS にもちゃんと書いてあった。コード例がないから理解できていないだけだった。
学んだこと2
最後の行で g を呼び出して再帰している部分は、ls をひとつずつ減らしながら逐次処理をしつつ、全部なくなったら args からひとつ持ってきてそれを ls にして・・・、という再帰になっていて、見事に再帰的なリスト処理をやってのけている。
今の僕ではどれだけ時間をかけて考えてもこのコードにはたどり着かない。
学んだこと3
f とか g とか、結構いい加減な命名なのか。それとも慣習なんだろうか。
いずれにせよ、短い名前は良いことだ、ということがわかった。僕もこれから名前付き let では f とか g とかを使おう。