プログラミングGaucheの練習問題(入れ子リストへの手続き適用)

プログラミングGaucheの7.2の練習問題(P68)をしてみる。

for-each-numbersとmap-numbers

これらは、filter関数でnumberのみにフィルタリングされたリストに対して、for-eachまたはmapを適用するだけなので、以下のとうり。

(define (for-each-numbers pred lis)
  (for-each pred
    (filter number? lis)
  )
)
(define (map-numbers pred lis)
  (map pred
    (filter number? lis)
  )
)

上記のようにして、以下のようにテスト。

(print (map-numbers (lambda(x) (* x 2) ) '(1 2 #t 3 4) ) )
(map-numbers (lambda(x) ( print x ) ) '(1 2 #t 3 4) ) 
  • >
>gosh ./walker.scm
(2 4 6 8)
1
2
3
4

numbers-only

for-eachやmap等の手続きを受け取り、それらの手続きを数値だけに適当する手続きへと変換。
これも、数値だけにフィルタリングされたリストに対して、それらの手続きを適用するだけなので以下のとおり。

(define (numbers-only walker)
  (lambda (proc lis)
    (walker proc (filter number? lis)))
)

で、確認

(print ( (numbers-only map)  (lambda(x) (* x 2) ) '(1 2 #f 4 5) ) )
  • >
>gosh ./walker.scm
(2 4 8 10)

numbers-only-for-tree

入れ子リストに対して、numbers-onlyを適用したmap,for-eachが使えるかどうかという問題でした。
tree-walkはp65に以下のように定義されていました。
(こちらの写経ミスのためはまっていましました。。。)

(define (tree-walk walker proc tree)
  (walker (lambda (elt)
            (if (list? elt)
                (tree-walk walker proc elt)
                (proc elt)))
          tree))

上記のnumber-onlyでは、入れ子リストがフィルタリング結果に含まれないので、うまくいきません。
これは、要素がリストの場合、それに対してもmap,for-eachがネストして適用されるようにする必要があります。。
まず、入れ子リストを結果に含まれるようになるフィルタリング手続きを定義、map,for-eachがそれでフィルタリングされたリストのみを処理するようにしました。
(入れ子のリストに対応したフィルタリングというヒントはhttp://d.hatena.ne.jp/mohayonao/20080710/1215674923を参照させていただいた。
あとこちらの方は、ちょっと勘違いのようですね?

(define (filter-for-tree pred lis)
  (filter (lambda(x)  (or (pred x) (pair? x )) ) lis)
)

(define (numbers-only-for-tree walker)
  (lambda (proc lis)
    (walker proc (filter-for-tree number? lis)))
)

で、確認

 ( print ( tree-walk (numbers-only-for-tree map)
     (lambda (x) (* x 3 )) '(1 2 #f ()  ( 5  #f 6 (7 8) )  9 10))  )
  • >
>gosh ./walker.scm
(3 6 (15 18 (21 24)) 27 30)

応用-filtered-walker-for-tree

ついでに、number?ではなく、任意の判定のための手続きでフィルタリングできるパターンも実装

(define (filtered-walker-for-tree walker pred)
  (lambda (proc lis)
    (walker proc (filter-for-tree pred lis)))
)

で、確認

 ( print ( tree-walk 
    (filtered-walker-for-tree map (lambda(x) (and (number? x) (even? x) ))) 
    (lambda (x) (* x 3 )) '(1 2 #f ()  ( 5  #f 6)  3 4))  )
  • >
>gosh ./walker.scm
(6 (18) 12)