問題3-12〜14

「3.3 可変データでのモデル化」の節に入りました。
問題3-12で、append!の動きを確認します。

(define (append! x y)
  (set-cdr! (last-pair x) y)
  x)

(define (last-pair x)
  (if (null? (cdr x))
      x
      (last-pair (cdr x))))

(define x (list 'a 'b))
(define y (list 'c 'd))
(define z (append x y))

z  ;=>(a b c d)
(cdr x)  ;=>(b)

(define w (append! x y))

w  ;=>(a b c d)
(cdr x)  ;=>(b c d)

このような結果になることを、実際に実行するまで気づくことができませんでしたが、結果を見て納得しました。appendの方は、xとyの構造自体は変更せず、新しい対を生成しながら二つのリストを合成しています。そのため、append前後において、(cdr x)が指す内容に変化はありません。しかし、append!の方は、xの最後の対のcdrが指す内容を、nullからyに変更しています。そのため、append!実行後は、(cdr x)が指す内容にyのリストも含まれてしまいます。
問題3-13です。下記のようにmake-cycle手続きを定義して、それを利用してみます。

(define (make-cycle x)
  (set-cdr! (last-pair x) x)
  x)

(define a (make-cycle (list 'a 'b 'c)))

a  ;=>#0=(a b c . #0#)
(cdr a)  ;=>#0=(b c a . #0#)
(cdr (cdr a))  ;=>#0=(c a b . #0#)
(cdr (cdr (cdr a)))  ;=>#0=(a b c . #0#)

渡されたリストの最後尾の対で、cdrがnullではなく、先頭の対を指すように変更したため、並びが循環するようなデータができました。(last-pair z)を実行すると無限ループに陥ってしまいますが、その原因としては最終判定をcdrがnullとしているからだと思われます。
問題3-14のmysteryを使うと、渡されたリストの並びを反転させることができます。

(define (mystery x)
  (define (loop x y)
    (if (null? x)
        y
        (let ((temp (cdr x)))
          (set-cdr! x y)
          (loop temp x))))
  (loop x '()))

(define v (list 'a 'b 'c 'd))
v  ;=>(a b c d)

(define w (mystery v))
w  ;=>(d c b a)
v  ;=>(a)

最後のvの結果が(a)になってしまう件についてですが、これは、mystery内のloopの最初の(set-car! x y)で、xのcdrがnullに書き替えられてしまうからです。その後、このx自体を指すようなリストが出来上がってくるので、wのリストの最後尾の対と、vが指す対は同一なのではと推察することができます。