Assignment/Streams!


Read Section 4.7

Streams:

	A stream is a possibly infinite sequence of
values that allows access, if need be, to initial
values while later ones are still being generated.

Here is an ADT for streams

1. (stream-car stream) takes a nonempty stream and
returns the first element in the stream

2. (stream-cdr stream) takes a nonempty stream and
returns a STREAM that contains the same values as the
given stream, in the same order, less the first value

3. (make-stream v p) takes a value v and a procedere p
of no aruments and returns a new stream s such that 
(stream-car s) returns v and (stream-cdr s) is the
stream obtained by invoking p

4. the-null-stream  is the empty stream

5. stream-null? predicate for recognizing empty
streams. 



Difference between list interface (car cdr ...) and
stream interface is that the second argument to
make-stream is not the rest of the stream but a
procedure of no arguments that returns the rest of the
stream.

This delays the formation of the rest of the stream
until needed by stream-cdr.

THUNKS: procedures of no arguments used to delay
evaluation 



Small aside:

> (let ([foo (lambda (n)
	     (if (zero? n)
		 1
		 (* n (foo (sub1 n)))))])
  (foo 5))
     
> 


Error: variable foo is not bound.
Type (debug) to enter the debugger.
>

Instead you have to use 

	letrec


> (letrec ([foo (lambda (n)
	     (if (zero? n)
		 1
		 (* n (foo (sub1 n)))))])
  (foo 5))

> 120



Back to streams:

Apply a procedure proc to each value in the stream 

(define stream-for-each
  (lambda (proc stream)
    (letrec ([loop (lambda (stream)
		     (if (not (stream-null? stream))
			 (begin
			   (proc (stream-car stream))
			   (loop (stream-cdr stream)))))])
      (loop stream))))


(define display-stream
  (lambda (stream)
    (stream-for-each display stream)
    (newline)))



How about converting a string to a stream:

(define string->stream
  (lambda (string)
    (let ([string-len (string-length string)])
      (letrec ([loop (lambda (cursor)
		       (if (= cursor string-len)
			   the-null-stream
			   (make stream
			     (string-ref string cursor)
			     (lambda ()
			       (loop (add1 cursor))) )))])
	(loop 0) ))))




Stream to list

only for finite streams; otherwise this is an infinite
loop

(define stream->list
  (lambda (stream)
    (if (stream-null? stream)
	'()
	(cons (stream-car stream)
	  (stream->list (stream-cdr stream))))))

    



A stream filter that takes a predicate pred and
returns a STREAM consisting of those values from stream 
that satisfy pred

(define stream-filter
  (lambda (pred stream)
    (cond
      [(stream-null? stream) the-null-stream]
      [(pred (stream-car stream))
       (make-stream
	 (stream-car stream)
	 (lambda ()
	   (stream-filter
	     pred
	     (stream-cdr stream))))]
      [else (stream-filter pred (stream-cdr stream))])))


Infinite stream:

(define even-positive-integers
  (stream-filter even? positive-integers))
       
 


Reading input from terminal:

(define make-input-stream
  (lambda ()
    (let ([char (read-char)])
      (if (eof-object? char)
	  the-null-stream
	  (make-stream 
            char make-input-stream)))))


(define read-print
  (lambda ()
    (display "--> ")
    (display-stream (make-input-stream))
    (read-print)))




Implementation: for finite streams

Implement as list:

(define stream-car car)

(define stream-cdr cdr)

(define make-stream
  (lambda (val thunk)
    (cons val (thunk))))

(define the-null-stream '())

(define stream-null
  (lambda (stream)
    (eq? stream the-null-stream)))


If we do not know whether the stream
is finite or infinite:

(define stream-car car)

(define stream-cdr
  (lambda (stream)
    ((cdr stream))))

(define make-stream
  (lambda (val thunk)
    (cons val thunk)))

(define the-null-stream
  (make-stream
    "end-of-stream"
    (lambda () the-null-stream)))


If there are side effects, when you evaluate 
the thunk 

(define stream-cdr
  (lambda (stream)
    (if (pair? (cdr stream))
	(cdr stream)
	(let ([s ((cdr stream))])
	  (set-cdr! stream s)
	  s) )))

    

Sushil Louis
Last modified: Mon Nov 1 10:31:26 PST 1999