Exercise 3.52.

Exercise 3.52.

(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)

のそれぞれの式が評価された段階での sum の値とと出力を考える問題。
さらには delay がメモ化されない場合はどうなるかという 2 つ問題です。

メモ化される場合

一瞬考え込みましたが、 stream-map にしろ streadm-filter にしろ渡される関数が
評価されるのは結果の最初の要素が生成されたところまでということなので、次のようになるんだと思います。

(define sum 0)
; sum => 0
(define (accum x)
  (set! sum (+ x sum))
  sum)
; sum => 0
(define seq (stream-map accum (stream-enumerate-interval 1 20)))
; sum => 1
(define y (stream-filter even? seq))
; sum => 6 ( この時点で seq が 1, 2, 3 まで辿られた)
(define z (stream-filter (lambda (x) (= (remainder x 5) 0))
                         seq))
; sum => 10 (この時点で seq は 1, 2, 3, 4 まで辿られた)
(stream-ref y 7)
; => 136  (この時点で seq は 1, 2, 3, ..., 16 まで辿られた)
; sum => 136 
(display-stream z)
; 10 15  45 55 105 120 190 210 (z が全部辿られた→つまり seq も 1 ... 20 まで辿られた)
; sum => 210

メモ化されない場合

おぉ?! メモ化されない場合は seq が辿られる度に sum が足されていくって事で、何回も足されてしまうってことかいな?

ちょっと考える。

(define sum 0)
; sum => 0
(define (accum x)
  (set! sum (+ x sum))
  sum)
; sum => 0
(define seq (stream-map accum (stream-enumerate-interval 1 20)))
; sum => 1

ここまではメモ化される場合と同じ。

そして

(define y (stream-filter even? seq))

について。初めの段階で seq は (1 . #) で 1 は奇数なので、(stream-cdr seq) を評価する(※ sum = 1) 。

(stream-cdr seq) は (3 . #) なので更に stream-cdr を評価する(※ sum = 3)。

その次は (6 . #) となり、6 は偶数なので、ここで終わり(※ sum = 6)。

(define z (stream-filter (lambda (x) (= (remainder x 5) 0))
                         seq))

そして、これ。現時点で sum が 6。しかもメモ化されていないって事は seq (1 . #) で closure が評価されると accum が評価されて sum の値は 6 + 2 = 8 になる。つづいて 8 + 3 = 11, 11 + 4 = 15 となり、ここでストップ。z は (15 . #)。(※ sum = 15)

(stream-ref y 7)

について。この時点で sum は 15 であり、y は 3 まで辿って (6 . #) となっているので、この後は

(19 24 30 37 45 54 64 75 87 100 114 129 145 162 ...

とつづく。実際には 6 が入るので (stream-ref y 7) は 162(※ sum = 162)。

最後に

(display-stream z)

これ。この時点で sum は 162 で z は 4 までだとって (15 . #) なので、この後 seq は

(167 173 180 188 197 207 218 230 243 257 272 288 305 323 342 362)

と続く。z の最初の要素 15 を併せると出力されるのは

15 180 230 305

となり、この時点での sum の値は 362。

あー疲れた。

面倒くさかった。stream を表すところでひとまとめに # と書いてますが、文脈によってそれぞれが含んでいる手続きは異なることに注意です。