sicp/3-5.org
2014-10-30 22:30:31 -04:00

300 lines
7.7 KiB
Org Mode

#+TITLE: 3.5 - Streams
#+BEGIN_HTML
<script type="text/javascript"
src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
</script>
#+END_HTML
* Streams are Delayed Lists
#+begin_src scheme
(define (cons-stream a b)
(cons a (delay b)))
(define (stream-car s)
(car s))
(define (stream-cdr s)
(force (cdr s)))
(define the-empty-stream '())
(define (stream-ref s n)
(if (= n 0)
(stream-car s)
(stream-ref (stream-cdr s) (- n 1))))
(define (stream-map proc s)
(if (stream-null? s)
the-empty-stream
(cons-stream (proc (stream-car s))
(stream-map proc (stream-cdr s)))))
(define (stream-for-each proc s)
(if (stream-null? s)
'done
(begin (proc (stream-car s))
(stream-for-each proc (stream-cdr s)))))
#+end_src
#+begin_src scheme :tangle yes
;; ===================================================================
;; 3.5.1: Streams are Delayed Lists
;; ===================================================================
(define (display-stream s)
(stream-for-each display-line s))
(define (display-line x)
(newline)
(display x))
(define (stream-enumerate-interval low high)
(if (> low high)
the-empty-stream
(cons-stream
low
(stream-enumerate-interval (+ low 1) high))))
(define (stream-filter pred stream)
(cond ((stream-null? stream) the-empty-stream)
((pred (stream-car stream))
(cons-stream (stream-car stream)
(stream-filter pred
(stream-cdr stream))))
(else (stream-filter pred (stream-cdr stream)))))
#+end_src
** Exercise 3.50
Complete the following definition, which generalizes `stream-map' to
allow procedures that take multiple arguments, analogous to `map' in
section *Note 2-2-3::, footnote *Note Footnote 12::.
#+begin_src scheme
(define (stream-map proc . argstreams)
(if (<??> (car argstreams))
the-empty-stream
(<??>
(apply proc (map <??> argstreams))
(apply stream-map
(cons proc (map <??> argstreams))))))
#+end_src
----------------------------------------------------------------------
#+begin_src scheme
;; -------------------------------------------------------------------
;; Exercise 3.50
;; -------------------------------------------------------------------
(define (stream-map proc . argstreams)
(if (stream-null? (car argstreams))
the-empty-stream
(cons-stream
(apply proc (map stream-car argstreams))
(apply stream-map
(cons proc (map stream-cdr argstreams))))))
#+end_src
** Exercise 3.51
In order to take a closer look at delayed
evaluation, we will use the following procedure, which simply
returns its argument after printing it:
#+begin_src scheme
(define (show x)
(display-line x)
x)
#+end_src
What does the interpreter print in response to evaluating each
expression in the following sequence?(7)
#+begin_src scheme
(define x (stream-map show (stream-enumerate-interval 0 10)))
(stream-ref x 5)
(stream-ref x 7)
#+end_src scheme
----------------------------------------------------------------------
#+begin_src scheme
(define x (stream-map show (stream-enumerate-interval 0 10)))
; 9
; 8
; 7
; 6
; 5
; 4
; 3
; 2
; 1
; 0
;Value: x
(stream-ref x 5)
;Value: 5
(stream-ref x 7)
;Value: 7
#+end_src
** Exercise 3.52
Consider the sequence of expressions
#+begin_src scheme
(define sum 0)
(define (accum x)
(set! sum (+ x sum))
sum)
(define seq (stream-map accum (stream-enumerate-interval 1 20)))
(define y (stream-filter even? seq))
(define z (stream-filter (lambda (x) (= (remainder x 5) 0))
seq))
(stream-ref y 7)
(display-stream z)
#+end_src
What is the value of `sum' after each of the above expressions is
evaluated? What is the printed response to evaluating the
`stream-ref' and `display-stream' expressions? Would these responses
differ if we had implemented `(delay <EXP>)' simply as `(lambda ()
<EXP>)' without using the optimization provided by `memo-proc'?
Explain
----------------------------------------------------------------------
#+begin_example
1 ]=> sum
;Value: 210
1 ]=> (stream-head y 10)
;Value 18: (210 204 200 182 174 144 132 90 74 20)
1 ]=> (display-stream z)
210
200
195
165
155
105
90
20
;Value: done
#+end_example
After the definition of =seq=, =sum= is equal to 210. It remains at
210 through the remainder of the operations.This would not be the
case if delay were not memoized, as without being so it would be
recalculated each time the items in the node were resolved, adding to
the value of =sum= each time, and changing the results captured by =y=
and =z=.
* 3.5.2 Infinite Streams
#+begin_src scheme :tangle yes
;; ===================================================================
;; 3.5.2: Infinite Streams
;; ===================================================================
(define (integers-starting-from n)
(cons-stream n (integers-starting-from (+ n 1))))
(define integers (integers-starting-from 1))
(define (divisible? x y) (= (remainder x y) 0))
(define no-sevens
(stream-filter (lambda (x) (not (divisible? x 7)))
integers))
(define (fibgen a b)
(cons-stream a (fibgen b (+ a b))))
(define fibs (fibgen 0 1))
(define (sieve stream)
(cons-stream
(stream-car stream)
(sieve (stream-filter
(lambda (x)
(not (divisible? x (stream-car stream))))
(stream-cdr stream)))))
(define primes (sieve (integers-starting-from 2)))
#+end_src
** Defining streams implicitly
#+begin_src scheme :tangle yes
(define ones (cons-stream 1 ones))
(define (add-streams s1 s2)
(stream-map + s1 s2))
(define integers (cons-stream 1 (add-streams ones integers)))
(define fibs
(cons-stream 0
(cons-stream 1
(add-streams (stream-cdr fibs)
fibs))))
(define (scale-stream stream factor)
(stream-map (lambda (x) (* x factor)) stream))
(define double (cons-stream 1 (scale-stream double 2)))
(define primes
(cons-stream
2
(stream-filter prime? (integers-starting-from 3))))
(define (prime? n)
(define (iter ps)
(cond ((> (square (stream-car ps)) n) true)
((divisible? n (stream-car ps)) false)
(else (iter (stream-cdr ps)))))
(iter primes))
#+end_src
*** Exercise 3.53
Without running the program, describe the elements of the stream
defined by
#+begin_src scheme
(define s (cons-stream 1 (add-streams s s)))
#+end_src
----------------------------------------------------------------------
\[
\sum_{i=1}^\infty 2^i
\]
*** Exercise 3.54
Define a procedure `mul-streams', analogous to `add-streams', that
produces the elementwise product of its two input streams. Use this
together with the stream of `integers' to complete the following
definition of the stream whose nth element (counting from 0) is n + 1
factorial:
#+begin_src scheme
(define factorials (cons-stream 1 (mul-streams <??> <??>)))
#+end_src
----------------------------------------------------------------------
#+begin_src scheme :tangle yes
(define (mul-streams s1 s2)
(stream-map * s1 s2))
(define factorials (cons-stream 1 (mul-streams (add-streams ones integers) factorials)))
#+end_src
*** Exercise 3.55
Define a procedure `partial-sums' that takes as argument a stream S
and returns the stream whose elements are S_0, S_0 + S_1, S_0 + S_1 +
S_2, .... For example, `(partial-sums integers)' should be the stream
1, 3, 6, 10, 15, ....