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