I think you should replace STREAM-DEFINE with a non-DEFINE version.
In introducing STREAM-DEFINE the SRFI says:
... with the (delay (force ...)) hidden within stream-define, which
is the syntax used to create a function that returns a stream:
The problem is that STREAM-DEFINE is syntax used to define a function
that returns a stream, not just to create such a function. What about
the LAMBDA's that are not the value in a DEFINE? Not to mention those
benighted individuals who don't like the (DEFINE (F ...) ...) syntax
in the first place.
You could replace STREAM-DEFINE with STREAM-DELAY:
(define-syntax stream-delay
(syntax-rules ()
((stream-delay x)
(make-stream (delay (force (stream-promise x)))))))
Then (stream-define (foo a b) stuff) could be written as
(define (foo a b) (stream-delay stuff))
which has the advantage of making it possible to control which expressions
get delayed and which don't. But mostly, it makes it clearer what is going
on. Unless I am missing something the code in the SRFI uses STREAM-DEFINE
more often than necessary. Take MAP2 and COUNTDOWN2 from the initial
explanation of even and odd streams:
(define (map2 func strm)
(delay (force (if (nil2? strm)
nil2
(cons2 (func (car1 strm))
(map2 func (cdr2 strm)))))))
(define (countdown2 n)
(delay (force (cons2 n (countdown2 (- n 1))))))
The DELAY-FORCE in MAP2 is needed to delay the call to NIL2?. Without
it MAP2 wouldn't return a fully-lazy stream. But the DELAY-FORCE in
COUNTDOWN2 is only delaying a CONS2 expression, which expands into a
DELAY. There is no utility in delaying the creation of a delay.
The reference implementation itself uses STREAM-DEFINE in many places
where DEFINE would work, including the definitions of STREAM-FROM,
STREAM-FROM-TO, STREAM-REPEAT, and STREAM-ITERATE. Many of the
functions that do need a delay would benefit from moving the delay
after some initial error checks. For example, writing STREAM-UNIQ
using STREAM-DELAY allows it to signal errors when it is called
instead of waiting until the result is forced:
(define (stream-uniq eql? strm)
(if (not (procedure? eql?))
(stream-error "non-functional argument to uniq"))
(if (not (stream? strm))
(stream-error "non-stream argument to uniq"))
(stream-delay (if (stream-null? strm)
stream-null
(let ((first (stream-car strm)))
(stream-cons first
(stream-uniq-aux eql? strm first)))))
-Richard Kelsey