問題3-15〜18
対が指す場所が等しいのか、データを指している対は同一なのか否か、ということに対する考察を深めていく部分です。
問題3-15は、set-to-wow!の効果を説明せよとのことです。
(define (set-to-wow! x) (set-car! (car x) 'wow) x) (define x (list 'a 'b)) (define z1 (cons x x)) (define z2 (cons (list 'a 'b) (list 'a 'b))) (eq? (car (car z1)) (car (cdr z1))) ;=>#t (eq? (car (car z2)) (car (cdr z2))) ;=>#t z1 ;=>((a b) a b) (set-to-wow! z1) ;=>((wow b) wow b) z2 ;=>((a b) a b) (set-to-wow! z2) ;=>((wow b) a b) (eq? (car (car z1)) (car (cdr z1))) ;=>#t (eq? (car (car z2)) (car (cdr z2))) ;=>#f
set-to-wow!に渡されたリストのcarの対のcarを変更しますが、z1は最初に渡されたリストのcarもcdrも同一なので、set-car!による変更で、上記のような結果が返ってきます。逆に、z2の方は、car/cdrの対自体が違うので、変更対象となるのは、その一方のみとなります。
問題3-16は、対の個数を数える問題です。Benのロジックが正しくないことを示す例を書いてみます。
(define (count-pairs x) (if (not (pair? x)) 0 (+ (count-pairs (car x)) (count-pairs (cdr x)) 1))) (define x1 (list 'a 'b 'c)) (count-pairs x1) ;=>3 (define x2-list (list 'a 'b)) (define x2 (cons x2-list (cdr x2-list))) (count-pairs x2) ;=>4 (define x3-list1 (cons 'a 'b)) (define x3-list2 (cons x3-list1 x3-list1)) (define x3 (cons x3-list2 x3-list2)) (count-pairs x3) ;=>7
全て、対自体は三つですが、count-pairsから返ってくる答えが異なってしまいます。同一の対を重複してカウントしてしまうことが原因です。
問題3-17で、これを改善します。一度カウントした対は、それを一時リストに登録しておき、探索途中でその一時リストを調べるようにします。(一時リストのそれぞれの対のcarが指し示す対が、既にカウントされている対ということになります。)
(define (count-pairs x) (define counted-pairs '()) (define (is-counted? counted target) (cond ((null? counted) #f) ((eq? (car counted) target) #t) (else (is-counted? (cdr counted) target)))) (define (inner-count-pairs p) (cond ((not (pair? p)) 0) ((is-counted? counted-pairs p) 0) (else (set! counted-pairs (cons p counted-pairs)) (+ (inner-count-pairs (car p)) (inner-count-pairs (cdr p)) 1)))) (inner-count-pairs x)) (count-pairs x1) ;=>3 (count-pairs x2) ;=>3 (count-pairs x3) ;=>3
問題3-18は、リストに循環が含まれているかどうかを調べる検査ロジックを書く問題です。これも、先頭の対を一時データとして保存しておき、リスト探索中にそれと等しくないかを調べていく流れで書きました。(最初の対を一時データに登録する部分が、いまいちすっきりと書けませんでした)
(define (is-cycle? x) (define start-pair '()) (define (iter p) (cond ((null? p) #f) ((eq? p start-pair) #t) (else (if (null? start-pair) (set! start-pair p)) (iter (cdr p))))) (iter x)) (is-cycle? (list 'a 'b 'c)) ;=>#f (is-cycle? (make-cycle (list 'a 'b 'c))) ;=>#t
問題3-19は、思考を深めることができなかったため飛ばしました。
また、問題3-20は、また環境の図を書かせる問題ですが、おそらくconsを評価する時に作成される環境にxやyが束縛されていて、その環境をベースにset-car!やset-cdr!が評価されるので、別のconsを定義したとしても、お互いの構成データが干渉しあうことはない、ということなんだろうと思います。