9章3節。
id:yagiey:20090309:1236597268の最後で挙げた3つの手続きは、以下の共通部分を持つ。
(lambda (elt lis . optionals) (let-optionals* optionals ((cmp-fn equal?)) (define loop (lmabda (lis) (cond ((null? lis) ○○) ((cmp-fn elt (△△ lis)) (□□ lis)) (else ☆☆)))) (loop lis)))
違うのは○○、△△、、□□、☆☆の箇所だけ。
じゃあ○○、△△、□□、☆☆を引数で受け取って、手続きを返せば良くね?と。
そうすれば何度も同じソースコード書かなくて済むじゃん!みたいな。
ってことで、○○をfallback、△△をget-key、□□をreturn、☆☆をrepeatと名付けて、my-memberやdelete-1やmy-assocみたいな手続きを返すtraverse手続きを書いてみよう、と。
(define traverse (lambda (fallback get-key return repeat) (lambda (elt lis . optionals) (let-optionals* optionals ((cmp-fn equal?)) (define loop (lambda (lis) (cond ((null? lis) fallback) ((cmp-fn elt (get-key lis)) (return lis)) (else (repeat loop lis))))) (loop lis)))))
ってな感じ。
repeatの部分は、loopを引数で受け取らないといけないので、単純に
(else ☆☆)
じゃないけど。
このtraverseを使えば、member、delete-1、my-assocは
(define my-member (traverse #f car (lambda (x) x) (lambda (loop lis) (loop (cdr lis))))) (define delete-1 (traverse '() car cdr (lambda (loop lis) (cons (car lis) (loop (cdr lis)))))) (define my-assoc (traverse #f (lambda (p) (car (car p))) car (lambda (loop lis) (loop (cdr lis)))))
ってできるね、ということらしい。
いいねーっ!楽チン。
本書ではtraverseでmember2を作る時に、returnにvalues手続きを渡しているのが不思議だった。
ってことで、valudesで返した多値をrecieveで受け取らなかったらどうなるか実験してみた。
gosh> (cdr (values '(foo bar) '(baz qux))) (bar)
1つ目の値が使われるみたいだね。