SICP p.206

SchemeSICP(計算機プログラムの構造と解釈) p.206 ですが、

(define (solve f y0 dt)
  (define y (integral (delay dy) y0 dt))
  (define dy (stream-map f y))
  y)

これが、本に載っているソースコードで、最新の Gauche 0.8.12 だと動かないのに、0.8.3 だと動く。ビックリ。y と dy が相互に参照していることが問題です。

(define (solve f y0 dt)
  (define y #f)
  (define dy (stream-map f y))
  (define y (integral (delay dy) y0 dt))
  y)

という感じで、ダミーのデータを y に入れておくと、0.8.12 でも動いちゃいます。

(define (solve f y0 dt)
  (letrec
      ((y (integral (delay dy) y0 dt))
      (dy (stream-map f y)))
    y))

Scheme の仕様の範囲内での書き方です。letrec を使うと、相互に参照できます。注71で動かない処理系がありますと書いてあるけれど、注意書きを書くくらいなら letrec 使おうよ>作者さん。

以下、今日、書いた(打ち込んだ)コード。微分方程式 dy/dt = y を、初期値 y(0) = 1 で解き、e を計算します。遅延評価を使って無限の長さのリストを作り出しています。

(define-syntax cons-stream (
  syntax-rules () ((_ a b) (cons a (delay b)))))
(define the-empty-stream '())
(define (stream-car stream) (car stream))
(define (stream-cdr stream) (force (cdr stream)))
(define (stream-null? stream) (null? stream))
(define (add-streams s1 s2) (stream-map + s1 s2))
(define (stream-ref s n)
  (if (= n 0)
    (stream-car s)
    (stream-ref (stream-cdr s) (- n 1))))
(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))))))
(define (scale-stream stream factor)
  (stream-map (lambda (x) (* x factor)) stream))
(define (integral delay-integrand initial-value dt)
  (define int
    (cons-stream initial-value
      (let ((integrand (force delay-integrand)))
        (add-streams 
          (scale-stream integrand dt)
          int))))
  int)
(define (solve f y0 dt)
  (letrec
      ((y (integral (delay dy) y0 dt))
      (dy (stream-map f y)))
    y))
(stream-ref (solve (lambda (y) y) 1 0.001) 1000)