Если вы не хотите идти по макро-маршруту, вы всегда можете просто отказаться от cons-stream
и переписать lazy-list
следующим образом:
(define (lazy-list from)
(cons from (λ() (lazy-list (+ from 1)))))
Это, пожалуй, самое простое, наиболее прагматичное решение, но оно подходит только для составления ленивых списков увеличивающихся чисел. Вы можете обобщить это, передав функцию, которая будет вызывать последовательные элементы списка при вызове:
(define (lazy-list-gen generator)
(cons (generator)
(λ() (lazy-list-gen generator))))
(define (lazy-list from)
(lazy-list-gen
(λ()
(let ((ret from))
(set! from (+ from 1))
ret))))
Это работает довольно хорошо:
> (define x (lazy-list 1))
> (car-stream x)
1
> (car-stream (cdr-stream x))
2
Но в коде есть ошибка:
... continuing from above ...
> (car-stream (cdr-stream x))
3
Эта ошибка возникает из-за того, что вызов cdr-stream
снова вызывает generator
. Мы можем решить эту проблему, кэшируя возвращаемое значение лямбды:
(define (lazy-list-gen generator)
(cons (generator)
(let ((gen-cache #f))
(λ()
(cond ((not gen-cache)
(set! gen-cache (lazy-list-gen generator))))
gen-cache))))
Теперь все работает как надо:
> (define x (lazy-list 1))
> (car-stream x)
1
> (car-stream (cdr-stream x))
2
> (car-stream (cdr-stream x))
2
> (car-stream (cdr-stream (cdr-stream x)))
3
> (car-stream (cdr-stream x))
2