今までは"時間"の観点から現実世界をモデル化していたところを、別の視点からやってみましょう、というお話。具体的には(遅延)ストリームです。
前準備
サイトに載ってないコードだけ。
(define the-empty-stream '()) (define (stream-null? s) (eq? s the-empty-stream)) (define-syntax cons-stream (syntax-rules () ((_ x y) (cons x (delay y))))) ; メモ化しない版 ;(define-syntax delay ; (syntax-rules () ; ((_ x) ; (lambda () x)))) (define-syntax delay (syntax-rules () ((_ x) (memo-proc (lambda () x)))))
3.50 (stream-map)
(define (stream-map proc . argstreams) (if (stream-null? (car argstreams)) the-empty-stream (cons-stream (apply proc (map stream-car argstreams)) (apply stream-map (cons proc (map stream-cdr argstreams))))))
3.51
(define x (stream-map show (stream-enumerate-interval 0 10))) (stream-ref x 5) ; => 1 2 3 4 5 (stream-ref x 7) ; => 6 7
必要になった分だけアクセスしている。かっこいー
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) (zero? (remainder x 5))) seq))
これはdelayがメモ化する場合
(stream-ref y 7) ; => 136 (display-stream z) ; => 10 ; 15 ; 45 ; 55 ; 105 ; 120 ; 190 ; 210 ; done sum ; => 210
となって、メモ化しない場合
(stream-ref y 7) ; => 162 (display-stream z) ; => 15 ; 180 ; 230 ; 305 ; done sum ; => 362
となる。メモ化している方が自然な結果になっている。1本のストリームから複数のストリームに流れを渡すときに、いったん値が確定したところの値が変わっちゃいけない。set!による時間に依存してたらストリームにした意味がないもんな。