Gauche の手続き : 2

呼称: 高階手続き
目的: 高階手続きを学ぶ

手続きを受け取る手続きや、手続きを返す手続きを高階手続きと呼びます。Scheme では手続きを基本的な構成要素として、高階手続きを組み合わせることで大きなシステムを作成する。

言葉では簡単そうに説明されているけれど、いざ自分で考えてみると、理解できていない。本書のサンプルを写経して練習問題にチャレンジ。習うより慣れろ(- -#

;; 数値とそれ以外が混ざったリストから数値だけに手続きを適用する
(define (for-each-numbers proc lis)
  (for-each (lambda (x) (if (number? x) (proc x))) lis))

Gauche の手続き : 1で取り組んだ練習問題の、上記の結果をリストにします。よくよく問題を読むと「filter を使用して、、、」とありました(^ ^;;

;; 数値とそれ以外が混ざったリストから数値だけに手続きを適用したリストを返す
(use srfi-1)
(define (map-numbers proc lis)
  (map proc (filter number? lis)))

gosh> (map-numbers (lambda (x) (* x 2)) '(1 2 #f 3 4 #t))
(2 4 6 8)

filter を使えば、簡単にできました。さらに for-each や map 等の手続きを取る手続きを考えます。空きピースにはまるような感じですっきりしたコードになります。何か凄い。

;; for-eachやmap等の手続きを受け取り数値だけに適用する手続きへと変換する
(define (numbers-only no-proc)
  (lambda (ac-proc lis)
    (no-proc ac-proc (filter number? lis))))

gosh> ((numbers-only for-each) print '(1 2 #f 3 4 #t))
1
2
3
4
#<undef>
gosh> ((numbers-only map) (lambda (x) (* x 2)) '(1 2 #f 3 4 #t))
(2 4 6 8)

入れ子のリストを考慮した場合。map の <#undef> を返さない方法が分からない、、、という考え方自体が違うような気もする。

;; 数値とそれ以外が混じっている入れ子のリストの数値にだけ適用する
(define (numbers-only-for-tree walker proc lis)
  (walker (lambda (elt)
            (cond [(list? elt) (walker proc (filter number? elt))]
                  [(number? elt) (proc elt)]
                  ))
          lis))

gosh> (numbers-only-for-tree for-each print '(1 2 (3 #f 5) 6 #t (8 #t)))
1
2
3
5
6
8
#<undef>
gosh> (numbers-only-for-tree map (lambda (x) (* x 2)) '(1 2 (3 #f 5) 6 #t (8 #t)))
(2 4 (6 10) 12 #<undef> (16))