プログラミング Gauche - 9 章

1 節の練習問題でいきなり詰まりました。cons でリストのコピーを行わずに要素を探します。まったくお手上げだったのですが、Kahua のページに解答が載っていました。


(define (delete-1 elt lis . options)
(let-optionals* options ((cmp-fn equal?))
(define (loop lis)
(cond [(null? lis) '()]
[(cmp-fn elt (car lis)) (cdr lis)]
[else (let ((tail (loop (cdr lis))))
(if (eq? tail (cdr lis))
lis
(cons (car lis) tail)))]))
(loop lis)))
(cdr lis) を引数に再帰呼び出しを行った結果を tail に束縛し、元の (cdr lis) と比較して同一オブジェクトだった場合はそのまま lis を返すようです。こうすれば元ソースのように (car lis) と cons しないため、コピーが発生しないということですね。
こういう、処理を再帰的に行った結果を呼び出し元で評価という考え方がなかなか出来ません。この場合は一致する要素が見つからない場合要素を末尾まで辿り、リストの先頭に戻りながら値を評価していくという処理が直感的に思い浮かばないのですね。とにかく今はサンプルコードをよく読んで、真似して書くしかないですね。

プログラミング Gauche - 8 章

真偽判定について。3 節の練習問題をやってみました。
手続きを返す手続きなので、内部は lambda になります。受け取る引数は可変長引数で、中身は手続きのリストです。引数として受け取った全ての手続きを(lambda の)引数に適用した結果、一つでも真値があれば全体として真を返すことになります。


(define (any-pred . pred) ; 可変長引数を受け取る手続き
(lambda (arg) ; 中身全体は lambda で囲まれる
次は引数を順番に評価することになります。これは例によって再帰でリスト処理を行えばいいでしょう。再帰を行うためにローカルな手続きを定義して適当な名前に束縛します。引数として評価する引数(ややこしい)と、手続きのリストを渡します。

(define x (lambda (pred arg)
(if (pair? pred)
(cons ( (car pred) arg) (x (cdr pred) arg) )
'())))
引数として受け取った手続きを評価したい引数に適用し、その真偽値をリストとして返します。

(any (lambda (e) (equal? e #t)) (x pred arg))))
そして結果として受け取ったリストに対し、any で真偽判定を行ってあげれば全体としての真偽が得られるわけです。#f #t を判定する述語が解らなかった*1ので、lambda を渡しています。ここの比較は equal? でいいのかな?

gosh>((any-pred odd? positive?) 3) ;=> #t
gosh>((any-pred odd? positive?) 2) ;=> #t
gosh>((any-pred odd? positive?) -1) ;=> #t
gosh>((any-pred odd? positive?) -2) ;=> #f

every-pred の場合は最後のリストを判定している any を every にしてあげれば OK。ローカルな lambda が沢山出てきて見づらいけれど、本当はもっと簡潔な書き方が出来るのだと思います。

*1:true? とかいうものがあるのかと思った