理系学生日記

おまえはいつまで学生気分なのか

問題 3-52 (3.5.1 Streams Are Delayed Lists)

まず,各ステップで sum の値はどうなっているのか!

(define sum 0)
(define (accum x)
  (set! sum (+ x sum))
  sum)
(define seq (stream-map accum (stream-enumerate-interval 1 20)))
(define y (stream-filter even? seq))
(define z (stream-filter (lambda (x) (= (remainder x 5) 0))
                         seq))
(stream-ref y 7)
(display-stream z)

(stream-map accum (stream-enumerate-interval 1 20)) を実行する前はもちろん 0 な sum なんですけど,実行後にこの値は 1 になっています.これはもちろん,accum は stream-enumerate-interval の先頭要素 1 に対してしか評価されないからですね (stream-enumerate-interval 自体も 1 しか作らなくて,他は単に delayed-object になってるだけだけど).

(stream-filter even? seq) を評価すると,sum の値は 6 になっています.評価前の seq の状態は (1, delayed-objects) という形になっていますが,この中から偶数を探すために delayed-object が評価されていきます.delayed-object (delay stream-enumerate-interval) が評価されて,まず 2 が生成されまして,これが sum に足されます.そして次に,3 が stream の最初に設定されるときに,sum に 3 が足されるので,最終的に 1 + 2 + 3 = 6 になるというのが実情.

(stream-filter (lambda (x) (= (remainder x 5) 0))) が評価された後の sum の値は 10.もう stream の中で 1, 2, 3 は評価された後のものが memo 化されているだけですから,accum は呼び出されません.そのため,accum の呼び出しを伴うのは,stream-enumerate-interval によって 4 が生成されたとき.5 で 無名関数の値として #t が返るから,stream-filter の定義を返り見ると,6 までが生成されるわけで,この値は 6 + 4 + 5 + 6 = 21 になるはずなんだけど.わけわからん.