From: Phil Bewig <xxxxxx@swbell.net>
Date: Fri, 14 Feb 2003 15:55:59 +0100
I suppose your point is that the essence of a stream is
the delay/force mechanism, and my library offers no
easy access to just that mechanism by itself, only in
combination with lambda and variable binding.
Right. I had trouble understanding when to use STREAM-LAMBDA,
part because it does three different things.
[...] I think I prefer the name
make-stream, for consistency with make-string and
make-vector, and because stream-delay emphasizes
the implementation mechanism rather than the data
type.
Except that streams, like lists and unlike strings and vectors, aren't
made. Only pairs are made, using CONS. The problem for fully-lazy
streams is that you may need to delay the choice between returning (),
making a new pair, or returning some existing one. Calling the syntax
you use for this MAKE-STREAM seems misleading. You're using it for the
delay, not for the stream, if you follow me.
Thus I propose make-stream for the core and both
stream-lambda and stream-define for the derived
library.
I agree, except that I think STREAM-DELAY is a better name.
As to your other point, I may well have used
stream-define more often than necessary in the
reference implementation. I was responding to a
problem that shows up with this version of
stream-cons that was used in several preliminary
versions of the SRFI:
(define-syntax old-stream-cons
(syntax-rules ()
((old-stream-cons obj strm)
(if (not (stream? strm))
(stream-error "attempt to stream-cons onto non-stream object")
(make-stream (delay (cons obj strm)))))))
Yes, but this is a macro, not a procedure. Arguments to a macro get
evaluated when they are used. Arguments to procedure get evaluated before
the call.
(define-syntax foo
((foo x) (delay x)))
actually delays a computation, because X is some random expression. On the
other hand,
(define (foo x)
(delay x))
is equivalent to
(define (foo x)
(let ((y (delay x)))
(force y)
y))
because evaluating an (un-SET!) variable reference neither causes or is
affected by any side effects. Thus there is no premature evaluation if
a procedure checks that a argument that must be a stream actually is one.
The nice thing about STREAM-DELAY is that it makes it clear that what
is going on is a delay. You use it if you want to delay evaluating a
stream-valued expression and don't use it if there is nothing to delay.
Because streams are fully-lazy there is no need for a corresponding
STREAM-FORCE. The various stream primitives (STREAM-NULL?, STREAM-CAR,
and so forth) do the forcing.
-Richard