SICP問題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の値
- stream-ref, display-stream式の評価に応じて印字される値
- メモ化版と非メモ化版を使用した場合の違い
ついて述べる問題。
とりあえず何も考えずに実行。
まずはメモ化版を使用した場合
(define sum 0) (define seq (stream-map accum (stream-enumerate-interval 1 20))) ; seq sum ; 1 (define y (stream-filter even? seq)) ; y sum ; 6 (define z (stream-filter (lambda (x) (= (remainder x 5) 0)) seq)) ; z sum ; 10 (stream-ref y 7) ; 136 sum ; 136 (display-stream z) ; 10 ; 15 ; 45 ; 55 ; 105 ; 120 ; 190 ; 210done sum ; 210
次は非メモ化版を使用した場合
(define sum 0) (define seq (stream-map accum (stream-enumerate-interval 1 20))) ; seq sum ; 1 (define y (stream-filter even? seq)) ; y sum ; 6 (define z (stream-filter (lambda (x) (= (remainder x 5) 0)) seq)) ; z sum ; 15 (stream-ref y 7) ; 162 sum ; 162 (display-stream z) ; 15 ; 180 ; 230 ; 305done sum ; 362
何故違いが出るのかシミュレートしてみるとこんな感じ。
メモ化版のシミュレーション
(define seq (stream-map accum (stream-enumerate-interval 1 20))) ; => (stream-enumerate-interval 1 20) => (1) ; => (stream-map accum) => ((+ 0 1)) => (1), sum => 1 (define y (stream-filter even? seq)) ; => (stream-filter even? (1))=> () ; => (stream-enumerate-interval 1 20) => (1 2) ; => (stream-map accum) => (1 (+ 2 1)) => (1 3), sum => 3 ; => (stream-filter even?) => () ; => (stream-map accum) => seq => (1 3 (+ 3 3)) => (1 3 6), sum => 6 ; => (stream-filter even?) => (6) (define z (stream-filter (lambda (x) (= (remainder x 5) 0)) seq)) ; => (stream-filter (lambda (x) (= (remainder x 5) 0)) (1 3 6)) => () ; => (stream-enumerate-interval 1 20) => (1 2 3 4) ; => (stream-map accum) => seq => (1 3 6 (+ 4 6)) => (1 3 6 10), sum=> 10 ; => (stream-filter (lambda (x) (= (remainder x 5) 0)) (1 3 6 10)) => (10) (stream-ref y 7) ; => (stream-filter even?) => (6 10) ; => (stream-enumerate-interval 1 20) => (1 2 3 4 5) ; => (stream-map accum) => seq => (1 3 6 10 (+ 5 10)) => (1 3 6 10 15), sum => 15 ; => (stream-filter even?) => (6 10) ; => (stream-enumerate-interval 1 20) => (1 2 3 4 5 6) ; => (stream-map accum) => seq => (1 3 6 10 15 (+ 6 15)) => (1 3 6 10 15 21), sum => 21 ; => (stream-filter even?) => (6 10) ; => (stream-enumerate-interval 1 20) => (1 2 3 4 5 6 7) ; => (stream-map accum) => seq => (1 3 6 10 15 21 (+ 7 21)) => (1 3 6 10 15 21 28), sum => 28 ; => (stream-filter even?) => (6 10 28) ; => (stream-enumerate-interval 1 20) => (1 2 3 4 5 6 7 8) ; => (stream-map accum) => seq => (1 3 6 10 15 21 28 (+ 8 28)) => (1 3 6 10 15 21 36), sum => 36 ; => (stream-filter even?) => (6 10 28 36) ; => (stream-enumerate-interval 1 20) => (1 2 3 4 5 6 7 8 9) ; => (stream-map accum) => seq => (1 3 6 10 15 21 28 36 (+ 9 36)) => (1 3 6 10 15 21 36 45), sum => 45 ; => (stream-filter even?) => (6 10 28 36) ; => (stream-enumerate-interval 1 20) => (1 2 3 4 5 6 7 8 9 10) ; => (stream-map accum) => seq => (1 3 6 10 15 21 28 36 45 (+ 10 45)) => (1 3 6 10 15 21 36 45 55), sum => 55 ; => (stream-filter even?) => (6 10 28 36) ; => (stream-enumerate-interval 1 20) => (1 2 3 4 5 6 7 8 9 10 11) ; => (stream-map accum) => seq => (1 3 6 10 15 21 28 36 45 55 (+ 11 55)) => (1 3 6 10 15 21 36 45 55 66), sum => 66 ; => (stream-filter even?) => (6 10 28 36 66) ; => (stream-enumerate-interval 1 20) => (1 2 3 4 5 6 7 8 9 10 11 12) ; => (stream-map accum) => seq => (1 3 6 10 15 21 28 36 45 55 66 (+ 12 66)) => (1 3 6 10 15 21 36 45 55 66 78), sum => 78 ; => (stream-filter even?) => (6 10 28 36 66 78) ; => (stream-enumerate-interval 1 20) => (1 2 3 4 5 6 7 8 9 10 11 12 13) ; => (stream-map accum) => seq => (1 3 6 10 15 21 28 36 45 55 66 78 (+ 13 78)) => (1 3 6 10 15 21 36 45 55 66 78 91), sum => 91 ; => (stream-filter even?) => (6 10 28 36 66 78) ; => (stream-enumerate-interval 1 20) => (1 2 3 4 5 6 7 8 9 10 11 12 13 14) ; => (stream-map accum) => seq => (1 3 6 10 15 21 28 36 45 55 66 78 91 (+ 14 91)) => (1 3 6 10 15 21 36 45 55 66 78 91 105), sum => 105 ; => (stream-filter even?) => (6 10 28 36 66 78) ; => (stream-enumerate-interval 1 20) => (1 2 3 4 5 6 7 8 9 10 11 12 13 14 15) ; => (stream-map accum) => seq => (1 3 6 10 15 21 28 36 45 55 66 78 91 105 (+ 15 105)) => (1 3 6 10 15 21 36 45 55 66 78 91 105 120), sum => 120 ; => (stream-filter even?) => (6 10 28 36 66 78 120) ; => (stream-enumerate-interval 1 20) => (1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16) ; => (stream-map accum) => seq => (1 3 6 10 15 21 28 36 45 55 66 78 91 105 120 (+ 16 120)) => (1 3 6 10 15 21 36 45 55 66 78 91 105 120 136), sum => 136 ; => (stream-filter even?) => (6 10 28 36 66 78 120 136) ; (display-stream z) ; => (stream-filter (lambda (x) (= (remainder x 5) 0)) (1 3 6 10 15 21 36 45 55 66 78 91 105 120 136)) => (10 15 45 55 105 120) ; => (stream-enumerate-interval 1 20) => (1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17) ; => (stream-map accum) => seq => (1 3 6 10 15 21 28 36 45 55 66 78 91 105 120 136 (+ 17 136)) => (1 3 6 10 15 21 36 45 55 66 78 91 105 120 136 153), sum => 153 ; => (stream-filter (lambda (x) (= (remainder x 5) 0)) (1 3 6 10 15 21 36 45 55 66 78 91 105 120 136 153)) => (10 15 45 55 105 120) ; => (stream-enumerate-interval 1 20) => (1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18) ; => (stream-map accum) => seq => (1 3 6 10 15 21 28 36 45 55 66 78 91 105 120 136 153 (+ 18 153)) => (1 3 6 10 15 21 36 45 55 66 78 91 105 120 136 153 171), sum => 171 ; => (stream-filter (lambda (x) (= (remainder x 5) 0)) (1 3 6 10 15 21 36 45 55 66 78 91 105 120 136 153 171)) => (10 15 45 55 105 120) ; => (stream-enumerate-interval 1 20) => (1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19) ; => (stream-map accum) => seq => (1 3 6 10 15 21 28 36 45 55 66 78 91 105 120 136 153 171 (+ 19 171)) => (1 3 6 10 15 21 36 45 55 66 78 91 105 120 136 153 171 190), sum => 190 ; => (stream-filter (lambda (x) (= (remainder x 5) 0)) (1 3 6 10 15 21 36 45 55 66 78 91 105 120 136 153 171 190)) => (10 15 45 55 105 120 190) ; => (stream-enumerate-interval 1 20) => (1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20) ; => (stream-map accum) => seq => (1 3 6 10 15 21 28 36 45 55 66 78 91 105 120 136 153 171 190 (+ 20 190)) => (1 3 6 10 15 21 36 45 55 66 78 91 105 120 136 153 171 190 210), sum => 210 ; => (stream-filter (lambda (x) (= (remainder x 5) 0)) (1 3 6 10 15 21 36 45 55 66 78 91 105 120 136 153 171 190 210)) => (10 15 45 55 105 120 190 210)
非メモ化版のシミュレーション
(define seq (stream-map accum (stream-enumerate-interval 1 20))) ; => (stream-enumerate-interval 1 20) => (1) ; => (stream-map accum) => ((+ 0 1)) => (1), sum => 1 ; (define y (stream-filter even? seq)) ; => ※ seq は定義時に(1)となっているので更にaccumはされない ; => (stream-filter even? (1))=> () ; => (stream-enumerate-interval 1 20) => (1 2) ; => (stream-map accum) => (1 (+ 2 1)) => (1 3), sum => 3 ; => (stream-filter even?) => () ; => (stream-enumerate-interval 1 20) => (1 2 3) ; => (stream-map accum) => seq => (1 3 (+ 3 3)) => (1 3 6), sum => 6 ; => (stream-filter even?) => (6) (define z (stream-filter (lambda (x) (= (remainder x 5) 0)) seq)) ; => ※ seq は定義時に(1)となっているので更にaccumはされない ; => (stream-filter (lambda (x) (= (remainder x 5) 0)) (1)) => () ; => (stream-enumerate-interval 1 20) => (1 2) ; => (stream-map accum) => seq => (1 (+ 2 6)) => (1 8), sum => 8 ; => (stream-filter (lambda (x) (= (remainder x 5) 0)) (1 8)) => () ; => (stream-enumerate-interval 1 20) => (1 2 3) ; => (stream-map accum) => seq => (1 8 (+ 3 8)) => (1 8 11), sum => 11 ; => (stream-filter (lambda (x) (= (remainder x 5) 0)) (1 8 11)) => () ; => (stream-enumerate-interval 1 20) => (1 2 3 4) ; => (stream-map accum) => seq => (1 8 11 (+ 4 11)) => (1 8 11 15), sum => 15 ; => (stream-filter (lambda (x) (= (remainder x 5) 0)) (1 8 11 15)) => (15) (stream-ref y 7) ; => (stream-filter even?) => (6) ; => (stream-enumerate-interval 1 20) => (1 2 3 4) ; => (stream-map accum) => seq => (1 3 6 10 (+ 4 15)) => (1 3 6 10 19), sum => 19 ; => (stream-filter even?) => (6) ; => (stream-enumerate-interval 1 20) => (1 2 3 4 5) ; => (stream-map accum) => seq => (1 3 6 10 19 (+ 5 19)) => (1 3 6 10 24), sum => 24 ; => (stream-filter even?) => (6 24) ; => (stream-enumerate-interval 1 20) => (1 2 3 4 5 6) ; => (stream-map accum) => seq => (1 3 6 10 19 24 (+ 6 24)) => (1 3 6 10 24 30), sum => 30 ; => (stream-filter even?) => (6 24 30) ; => (stream-enumerate-interval 1 20) => (1 2 3 4 5 6 7) ; => (stream-map accum) => seq => (1 3 6 10 19 24 30 (+ 7 30)) => (1 3 6 10 24 30 37), sum => 37 ; => (stream-filter even?) => (6 24 30) ; => (stream-enumerate-interval 1 20) => (1 2 3 4 5 6 7 8) ; => (stream-map accum) => seq => (1 3 6 10 19 24 30 37 (+ 8 37)) => (1 3 6 10 24 30 45), sum => 45 ; => (stream-filter even?) => (6 24 30) ; => (stream-enumerate-interval 1 20) => (1 2 3 4 5 6 7 8 9) ; => (stream-map accum) => seq => (1 3 6 10 19 24 30 37 45 (+ 9 45)) => (1 3 6 10 24 30 45 54), sum => 54 ; => (stream-filter even?) => (6 24 30 54) ; => (stream-enumerate-interval 1 20) => (1 2 3 4 5 6 7 8 9 10) ; => (stream-map accum) => seq => (1 3 6 10 19 24 30 37 45 54 (+ 10 54)) => (1 3 6 10 24 30 45 64), sum => 64 ; => (stream-filter even?) => (6 24 30 54 64) ; => (stream-enumerate-interval 1 20) => (1 2 3 4 5 6 7 8 9 10 11) ; => (stream-map accum) => seq => (1 3 6 10 19 24 30 37 45 54 64 (+ 11 64)) => (1 3 6 10 24 30 45 64 75), sum => 75 ; => (stream-filter even?) => (6 24 30 54 64) ; => (stream-enumerate-interval 1 20) => (1 2 3 4 5 6 7 8 9 10 11 12) ; => (stream-map accum) => seq => (1 3 6 10 19 24 30 37 45 54 64 75 (+ 12 75)) => (1 3 6 10 24 30 45 64 75 87), sum => 87 ; => (stream-filter even?) => (6 24 30 54 64) ; => (stream-enumerate-interval 1 20) => (1 2 3 4 5 6 7 8 9 10 11 12 13) ; => (stream-map accum) => seq => (1 3 6 10 19 24 30 37 45 54 64 75 87 (+ 13 87)) => (1 3 6 10 24 30 45 64 75 87 100), sum => 100 ; => (stream-filter even?) => (6 24 30 54 64 100) ; => (stream-enumerate-interval 1 20) => (1 2 3 4 5 6 7 8 9 10 11 12 13 14) ; => (stream-map accum) => seq => (1 3 6 10 19 24 30 37 45 54 64 75 87 100 (+ 14 100)) => (1 3 6 10 24 30 45 64 75 87 100 114), sum => 114 ; => (stream-filter even?) => (6 24 30 54 64 100 114) ; => (stream-enumerate-interval 1 20) => (1 2 3 4 5 6 7 8 9 10 11 12 13 14 15) ; => (stream-map accum) => seq => (1 3 6 10 19 24 30 37 45 54 64 75 87 100 114 (+ 15 114)) => (1 3 6 10 24 30 45 64 75 87 100 114 129), sum => 129 ; => (stream-filter even?) => (6 24 30 54 64 100 114) ; => (stream-enumerate-interval 1 20) => (1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16) ; => (stream-map accum) => seq => (1 3 6 10 19 24 30 37 45 54 64 75 87 100 114 129 (+ 16 129)) => (1 3 6 10 24 30 45 64 75 87 100 114 129 145), sum => 145 ; => (stream-filter even?) => (6 24 30 54 64 100 114) ; => (stream-enumerate-interval 1 20) => (1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17) ; => (stream-map accum) => seq => (1 3 6 10 19 24 30 37 45 54 64 75 87 100 114 129 145 (+ 17 145)) => (1 3 6 10 24 30 45 64 75 87 100 114 129 145 162), sum => 162 ; => (stream-filter even?) => (6 24 30 54 64 100 114 162) ; (display-stream z) ; => (stream-filter (lambda (x) (= (remainder x 5) 0)) (1 8 11 15)) => (15) ; => (stream-enumerate-interval 1 20) => (1 2 3 4 5) ; => (stream-map accum) => seq => (1 8 11 15 (+ 5 162)) => (1 8 11 15 167), sum => 167 ; => (stream-filter (lambda (x) (= (remainder x 5) 0)) (1 8 11 15 167)) => (15) ; => (stream-enumerate-interval 1 20) => (1 2 3 4 5 6) ; => (stream-map accum) => seq => (1 8 11 15 167 (+ 6 167)) => (1 8 11 15 167 173), sum => 174 ; => (stream-filter (lambda (x) (= (remainder x 5) 0)) (1 8 11 15 167 173)) => (15) ; => (stream-enumerate-interval 1 20) => (1 2 3 4 5 6 7) ; => (stream-map accum) => seq => (1 8 11 15 167 173 (+ 7 173)) => (1 8 11 15 167 173 180), sum => 180 ; => (stream-filter (lambda (x) (= (remainder x 5) 0)) (1 8 11 15 167 174 182)) => (15 180) ; => (stream-enumerate-interval 1 20) => (1 2 3 4 5 6 7 8) ; => (stream-map accum) => seq => (1 8 11 15 167 173 180 (+ 8 180)) => (1 8 11 15 167 173 180 188), sum => 188 ; => (stream-filter (lambda (x) (= (remainder x 5) 0)) (1 8 11 15 167 173 180 188)) => (15 180) ; => (stream-enumerate-interval 1 20) => (1 2 3 4 5 6 7 8 9) ; => (stream-map accum) => seq => (1 8 11 15 167 173 180 188 (+ 9 188)) => (1 8 11 15 167 173 180 188 197), sum => 197 ; => (stream-filter (lambda (x) (= (remainder x 5) 0)) (1 8 11 15 167 173 180 188 197)) => (15 180) ; => (stream-enumerate-interval 1 20) => (1 2 3 4 5 6 7 8 9 10) ; => (stream-map accum) => seq => (1 8 11 15 167 173 180 188 197 (+ 10 197)) => (1 8 11 15 167 173 180 188 197 207), sum => 207 ; => (stream-filter (lambda (x) (= (remainder x 5) 0)) (1 8 11 15 167 173 180 188 197 207)) => (15 180) ; => (stream-enumerate-interval 1 20) => (1 2 3 4 5 6 7 8 9 10 11) ; => (stream-map accum) => seq => (1 8 11 15 167 173 180 188 197 207 (+ 11 207)) => (1 8 11 15 167 173 180 188 197 218), sum => 218 ; => (stream-filter (lambda (x) (= (remainder x 5) 0)) (1 8 11 15 167 173 180 188 197 207 218)) => (15 180) ; => (stream-enumerate-interval 1 20) => (1 2 3 4 5 6 7 8 9 10 11 12) ; => (stream-map accum) => seq => (1 8 11 15 167 173 180 188 197 207 218 (+ 12 218)) => (1 8 11 15 167 173 180 188 197 230), sum => 230 ; => (stream-filter (lambda (x) (= (remainder x 5) 0)) (1 8 11 15 167 173 180 188 197 207 218 230)) => (15 180 230) ; => (stream-enumerate-interval 1 20) => (1 2 3 4 5 6 7 8 9 10 11 12 13) ; => (stream-map accum) => seq => (1 8 11 15 167 173 180 188 197 207 218 230 (+ 13 230)) => (1 8 11 15 167 173 180 188 197 230 243), sum => 243 ; => (stream-filter (lambda (x) (= (remainder x 5) 0)) (1 8 11 15 167 173 180 188 197 207 218 230 243)) => (15 180 230) ; => (stream-enumerate-interval 1 20) => (1 2 3 4 5 6 7 8 9 10 11 12 13 14) ; => (stream-map accum) => seq => (1 8 11 15 167 173 180 188 197 207 218 230 243 (+ 14 243)) => (1 8 11 15 167 173 180 188 197 230 243 257), sum => 257 ; => (stream-filter (lambda (x) (= (remainder x 5) 0)) (1 8 11 15 167 173 180 188 197 207 218 230 243 257)) => (15 180 230) ; => (stream-enumerate-interval 1 20) => (1 2 3 4 5 6 7 8 9 10 11 12 13 14 15) ; => (stream-map accum) => seq => (1 8 11 15 167 173 180 188 197 207 218 230 243 257 (+ 15 257)) => (1 8 11 15 167 173 180 188 197 230 243 257 272), sum => 272 ; => (stream-filter (lambda (x) (= (remainder x 5) 0)) (1 8 11 15 167 173 180 188 197 207 218 230 243 257 272)) => (15 180 230) ; => (stream-enumerate-interval 1 20) => (1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16) ; => (stream-map accum) => seq => (1 8 11 15 167 173 180 188 197 207 218 230 243 257 272 (+ 16 272)) => (1 8 11 15 167 173 180 188 197 230 243 257 272 288), sum => 288 ; => (stream-filter (lambda (x) (= (remainder x 5) 0)) (1 8 11 15 167 173 180 188 197 207 218 230 243 257 272 288)) => (15 180 230) ; => (stream-enumerate-interval 1 20) => (1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17) ; => (stream-map accum) => seq => (1 8 11 15 167 173 180 188 197 207 218 230 243 257 272 288 (+ 17 288)) => (1 8 11 15 167 173 180 188 197 230 243 257 272 288 305), sum => 305 ; => (stream-filter (lambda (x) (= (remainder x 5) 0)) (1 8 11 15 167 173 180 188 197 207 218 230 243 257 272 288 305)) => (15 180 230 305) ; => (stream-enumerate-interval 1 20) => (1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18) ; => (stream-map accum) => seq => (1 8 11 15 167 173 180 188 197 207 218 230 243 257 272 288 305 (+ 18 305)) => (1 8 11 15 167 173 180 188 197 230 243 257 272 288 305 323), sum => 323 ; => (stream-filter (lambda (x) (= (remainder x 5) 0)) (1 8 11 15 167 173 180 188 197 207 218 230 243 257 272 288 305 323)) => (15 180 230 305) ; => (stream-enumerate-interval 1 20) => (1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19) ; => (stream-map accum) => seq => (1 8 11 15 167 173 180 188 197 207 218 230 243 257 272 288 305 323 (+ 19 323)) => (1 8 11 15 167 173 180 188 197 230 243 257 272 288 305 323 342), sum => 342 ; => (stream-filter (lambda (x) (= (remainder x 5) 0)) (1 8 11 15 167 173 180 188 197 207 218 230 243 257 272 288 305 323 342)) => (15 180 230 305) ; => (stream-enumerate-interval 1 20) => (1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20) ; => (stream-map accum) => seq => (1 8 11 15 167 173 180 188 197 207 218 230 243 257 272 288 305 323 342 (+ 20 342)) => (1 8 11 15 167 173 180 188 197 230 243 257 272 288 305 323 342 362), sum => 362 ; => (stream-filter (lambda (x) (= (remainder x 5) 0)) (1 8 11 15 167 173 180 188 197 207 218 230 243 257 272 288 305 323 362)) => (15 180 230 305)
ポイントは定義時にstream-carまで実行されることと、非メモ化版の方ではaccumが再度実行されるため、sumの値が何回も足されること。