7章2節の練習問題
for-each-numberとmap-numbersは簡単。
(define for-each-numbers (lambda (proc l) (for-each proc (filter number? l)))) (define map-numbers (lambda (proc l) (map proc (filter number? l))))
ですな。
これを、for-eachやmapを受け取ってfor-each-numbersやmap-numbersに相当する関数を返すnumbers-only関数を作れ、と。
これも簡単。
(define numbers-only (lambda (walker) (lambda (proc l) (walker proc (filter number? l)))))
関数を返すのでlambdaが1段増える。
さて、tree-walk関数(id:yagiey:20090206)の1つ目の引数に
(numbers-only map)
を渡しても、想定するように動かない。
filterがネストしたリストに対応していないため、例えば
gosh> ((numbers-only map) (lambda (n) n) '(a (1) ((b)) (((2))))) ()
ってなるんですな。これが根本的な原因。
だから、単純にfilterではなく、ネストしたリストに対応したfilter*を作って、filter*を使ってnumbers-onlyを書き換えればいいんじゃないだろうか。
ってことでfilter*とnumbers-only*を書いてみた。
(define filter* (lambda (proc l) (cond ((null? l) '()) ((list? (car l)) (cons (filter* proc (car l)) (filter* proc (cdr l)))) ((proc (car l)) (cons (car l) (filter* proc (cdr l)))) (else (filter* proc (cdr l)))))) (define numbers-only* (lambda (walker) (lambda (proc l) (walker proc (filter* number? l)))))
これを使ってtree-walkを動かしてみると
gosh> (tree-walk (numbers-only* map) (lambda (n) n) '(a (1) ((b)) (((3))) ((((#f 4)))))) ((1) (()) (((3))) ((((4)))))
だと。
うむ、うまくいってるんじゃないだろうか。
なんか、もっとエレガントな方法があるような気がするけど、とりあえずよしとする。