プログラミング Gauche - 7 章

2 節の練習問題をやってみた。数値とそれ以外のものが混じったリストから数値だけに手続きを適用する。


(define (for-each-numbers pred lis)
(for-each (lambda (elt)
(if (number? elt)
(pred elt)))
lis))
(for-each-numbers (lambda (x) (print (* x x))) '(1 2 #f 4 5 #t 7))

1
4
16
25
49

数値とそれ以外のものが混じったリストから数値だけに手続きを適用するが、map を使って結果をリストにする。


(define (map-numbers pred lis)
(map (lambda (elt)
(if (number? elt)
(pred elt)))
lis))
(map-numbers (lambda (x) (* x x)) '(1 2 #f 4 5 #t 7))

(1 4 #<undef> 16 25 #<undef> 49)

数値以外の時に何もしていないので、#<undef> までリストの要素になってしまう。何もしないで次の要素に処理を進めることってできないのかな?
やり方が解らないので再帰を使って自分で書いてみる。


(define (map-numbers pred lis)
(if (null? lis)
lis
(if (number? (car lis))
(cons (pred (car lis)) (map-numbers pred (cdr lis)))
(map-numbers pred (cdr lis)))))
(map-numbers (lambda (x) (* x x)) '(1 2 #f 4 5 #t 7))

(1 4 16 25 49)

正解なのかな。動いてはいるけれども。
次に、map や for-each の手続きを受け取って数値のみに適用する手続きに変換する手続きを書いてみる。意味がよく解らなかったのだけれど、map や for-each のラッパーを作ればいと解釈してみた。


(define (numbers-only pred)
(define (numbers lis)
(if (null? lis)
lis
(if (number? (car lis))
(cons (car lis) (numbers (cdr lis)))
(numbers (cdr lis)))))
(lambda (proc lis)
(pred proc (numbers lis))))
((numbers-only for-each) (lambda (x) (print (* x x))) '(1 2 #f 4 5 #t 7 #\8))

1
4
16
25
49

あらかじめ数値以外を削除した新しいリストを作っておき、pred に渡すラッパーにしてみた。
最後に、入れ子になったリストを辿る高階関数に numbers-only で作った手続きを渡してみる。


;; ツリーをたどる高階関数
(define (tree-walker walker proc tree)
(walker (lambda (elt)
(if (list? elt)
(tree-walker walker proc elt)
(proc elt)))
tree))
(tree-walker (numbers-only map) (lambda (x) (* x x)) '(1 2 (3 (4)) 5 (6 7 (8))))

(1 4 25)

numbers-only が数値のみのリストを作成するときに入れ子になっている部分を見ていないのが問題なんですね。再帰的に入れ子のリストを辿って、数値以外を削除したリストを作ればいいのかな?
ならば入れ子を辿る tree-walker に map を渡して、map の手続きに数値だけを返す手続きを渡せば……さっきと同じ問題にぶち当たってしまいました。リストから要素を削除するやり方がわかれば話は早いんですが。
ちょっとこの問題は先送りにして 7.3 に進みたいと思います。
解答例を見たかったのですが、本書の付録にもサポートページにも見当たりませんでした。解答例の公開を是非希望です。

うーん、今日もあんまり進みませんでした。ひげぽん氏がローベル本をさくさく読んでいるのを見てその進みの速さにちょっと嫉妬したり(笑

ドットファイルを表示するには

ホームに作った.fontsフォルダですが、このフォルダはどこにあるんでしょうか。ディスクトップにあるホームフォルダには入っていませんでした。あるけど属性の設定かなにかで見えないだけなのか、どこか別な場所にあるのかわかりませんが、とりあえずフォントのインストールは成功したので良しとしましょう。

ホームに作ったということですので、当然ですがホームに存在します。UnixLinux では、ドットで始まるファイルは主にシステムやアプリケーションの設定を記述するファイル(やディレクトリ)で、デフォルトでは表示されないようになっています。
Gnome のファイルマネージャの場合は Ctrl+h を押すか、「編集」「設定」「隠しファイルとバックアップファイル表示する」にチェックを入れると表示されるようになります。常に表示されるのはかなり鬱陶しい*1ので、その手のファイルをいじるときだけ Ctrl+h するのをおすすめします。
端末からの場合は

$ ls -a

と -a オプションをつけるとドットファイルやバックアップファイルが表示されます。

*1:やってみると解ります