[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: stream-define

This page is part of the web mail archives of SRFI 40 from before July 7th, 2015. The new archives for SRFI 40 contain all messages, not just those from before July 7th, 2015.

   From: Phil Bewig <pbewig@xxxxxxxxxx>
   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

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

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)

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.