מבוא מורחב למדעי המחשב בשפת Scheme תרגול 10 Streams 3.5, pages 316-352 definitions file on web 2 cons, car, cdr (define s (cons 9 (begin (display 7) 5))) -> prints 7 The display command is evaluated while evaluating the cons. (car s) -> 9 (cdr s) -> 5 3 cons-stream, stream-car, stream-cdr (define s (cons-stream 9 (begin (display 7) 5))) Due to the delay of the second argument, cons-stream does not activate the display command (stream-car s) -> 9 (stream-cdr s) -> prints 7 and returns 5 stream-cdr activates the display which prints 7, and then returns 5. 4 List enumerate (define (enumerate-interval low high) (if (> low high) nil (cons low (enumerate-interval (+ low 1) high)))) (enumerate-interval 2 8) -> (2 3 4 5 6 7 8) (car (enumerate-interval 2 8)) -> 2 (cdr (enumerate-interval 2 8)) -> (3 4 5 6 7 8) 5 Stream enumerate (define (stream-enumerate-interval low high) (if (> low high) the-empty-stream (cons-stream low (stream-enumerate-interval (+ low 1) high)))) (stream-enumerate-interval 2 8) -> (2 . #<promise>) (stream-car (stream-enumerate-interval 2 8)) -> 2 (stream-cdr (stream-enumerate-interval 2 8)) -> (3 . #<promise>) 6 List map (map <proc> <list>) (define (map proc s) (if (null? s) nil (cons (proc (car s)) (map proc (cdr s))))) (map square (enumerate-interval 2 8)) -> (4 9 16 25 36 49 64) 7 Stream map (map <proc> <stream>) (define (stream-map proc s) (if (stream-null? s) the-empty-stream (cons-stream (proc (stream-car s)) (stream-map proc (stream-cdr s)) ))) (stream-map square (stream-enumerate-interval 2 8)) -> (4 . #<promise>) 8 List of squares (define squares (map square (enumerate-interval 2 8))) squares -> (4 9 16 25 36 49 64) (car squares) -> 4 (cdr squares) -> (9 16 25 36 49 64) 9 Stream of squares (define stream-squares (stream-map square (stream-enumerate-interval 2 8))) stream-squares -> (4 . #<promise>) (stream-car stream-squares) -> 4 (stream-cdr stream-squares) -> (9 . #<promise>) 10 List reference (define (list-ref s n) (if (= n 0) (car s) (list-ref (cdr s) (- n 1)))) (define squares (map square (enumerate-interval 2 8))) (list-ref squares 3) -> 25 11 Stream reference (define (stream-ref s n) (if (= n 0) (stream-car s) (stream-ref (stream-cdr s) (- n 1)))) (define stream-squares (stream-map square (stream-enumerate-interval 2 8))) (stream-ref stream-squares 3) -> 25 12 List filter (filter <predicate> <list>) (define (filter pred s) (cond ((null? s) nil) ((pred (car s)) (cons (car s) (filter pred (cdr s)))) (else (filter pred (cdr s))))) (filter even? (enumerate-interval 1 20)) -> (2 4 6 8 10 12 14 16 18 20) 13 Stream filter (stream-filter <predicate> <stream>) (define (stream-filter pred s) (cond ((stream-null? s) the-empty-stream) ((pred (stream-car s)) (cons-stream (stream-car s) (stream-filter pred (stream-cdr s)))) (else (stream-filter pred (stream-cdr s))) ))) (stream-filter even? (stream-enumerate-interval 1 20)) 14 -> (2 . #<promise>) Generalized list map (generalized-map <proc> <list1> … <listn>) (define (generalized-map proc . arglists) (if (null? (car arglists)) nil (cons (apply proc (map car arglists)) (apply generalized-map (cons proc (map cdr arglists)))))) (generalized-map + squares squares squares) -> (12 27 48 75 108 147 192) 15 Generalized stream map (generalized-stream-map <proc> <stream1> … <streamn>) (define (generalized-stream-map proc . argstreams) (if (stream-null? (car argstreams)) the-empty-stream (cons-stream (apply proc (map stream-car argstreams)) (apply generalized-stream-map (cons proc (map stream-cdr argstreams)))))) (generalized-stream-map + stream-squares stream-squares stream-squares) -> (12 . #<promise>) 16 List for each (define (for-each proc s) (if (null? s) 'done (begin (proc (car s)) (for-each proc (cdr s))))) 17 Stream for each (define (stream-for-each proc s) (if (stream-null? s) 'done (begin (proc (stream-car s)) (stream-for-each proc (stream-cdr s))))) useful for viewing (finite!) streams (define (display-stream s) (stream-for-each display s)) (display-stream (stream-enumerate-interval 1 18 20)) -> prints 1 … 20 done Lists (define sum 0) (define (acc x) (set! sum (+ x sum)) sum) (define s (map acc (enumerate-interval 1 20))) s -> (1 3 6 10 15 21 28 36 45 55 66 78 91 105 120 136 153 171 190 210) sum -> 210 (define y (filter even? s)) y -> (6 10 28 36 66 78 120 136 190 210) sum -> 210 (define z (filter (lambda (x) (= (remainder x 5) 0)) s)) z -> (10 15 45 55 105 120 190 210) sum -> 210 19 (list-ref y 7) -> 136 sum -> 210 (display z) -> prints (10 15 45 55 105 120 190 210) sum -> 210 20 Streams (define sum 0) (define (acc x) (set! sum (+ x sum)) sum) (define s (stream-map acc (stream-enumerate-interval 1 20))) s -> (1 . #<promise>) sum -> 1 (define y (stream-filter even? s)) y -> (6 . #<promise>) sum -> 6 (define z (stream-filter (lambda (x) (= (remainder x 5) 0)) s)) z -> (10 . #<promise>) sum -> 10 21 (stream-ref y 7) -> 136 sum -> 136 (display-stream z) -> prints 10 15 45 55 105 120 190 210 done sum -> 210 22 Defining streams implicitly by delayed evaluation Suppose we needed an infinite list of Dollars. We can (define bill-gates (cons-stream ‘dollar bill-gates)) If we need a Dollar we can take the car (stream-car bill-gates) -> dollar The cdr would still be an infinite list of Dollars. (stream-cdr bill-gates)->(dollar . #<promise>) 23 Infinite Streams Formulate rules defining infinite series wishful thinking is key 24 1,1,1,… = ones = 1,ones (define ones (cons-stream 1 ones)) 25 2,2,2,… = twos = 2,twos (define twos (cons-stream 2 twos)) ones + ones adding two infinite series of ones (define twos (stream-map + ones ones)) 2 * ones element-wise operations on an infinite series of ones (define twos (stream-map (lambda (x) (* 2 x)) ones)) or (+ x x) 26 1,2,3,… = integers = 1,ones + integers 1,1,1… + 1,2,3,… 2,3,4,… (define integers (cons-stream 1 (stream-map + ones integers))) 27 0,1,1,2,3,… = fibs = 0,1,fibs + (fibs from 2nd position) 0,1,1,2,… + 1,1,2,3,… 1,2,3,5,… (define fibs (cons-stream 0 (cons-stream 1 (stream-map + fibs (stream-cdr fibs))))) 28 1,2,4,8,… = doubles = 1,doubles + doubles 1,2,4,8,… + 1,2,4,8,… 2,4,8,16,… (define doubles (cons-stream 1 (stream-map + doubles doubles))) 29 1,2,4,8,… = doubles = 1,2 * doubles (define doubles (cons-stream 1 (stream-map (lambda (x) (* 2 x)) doubles))) or (+ x x) 30 1,1x2,1x2x3,... = factorials = 1,factorials * integers from 2nd position 1, 1*2, 1*2*3,… x 2, 3, 4,… 1*2,1*2*3,1*2*3*4,… (define factorials (cons-stream 1 (stream-map * factorials (stream-cdr integers)))) 31 (1),(1 2),(1 2 3),… = runs = (1), append runs with a list of integers from 2nd position (1), (1 2), (1 2 3),… append (2), (3), (4),… (1 2),(1 2 3),(1 2 3 4),… (define runs (cons-stream (list 1) (stream-map append runs (stream-map list (stream-cdr integers))))) 32 a0,a0+a1,a0+a1+a2,… = partial sums = a0,partial sums + (stream from 2nd pos) a0, a0+a1, a0+a1+a2,… + a1, a2, a3,… a0+a1,a0+a1+a2,a0+a1+a2+a3,… (define (partial-sums a) (cons-stream (stream-car a) (stream-map + (partial-sums a) (stream-cdr a)))) 33 Partial Sums (cont.) (define (partial-sums a) (define sums (cons-stream (stream-car a) (stream-map + sums (stream-cdr a)))) sums) This implementation is more efficient since it uses the stream itself rather than recreating it recursively 34 Approximating the natural logarithm of 2 1 1 1 ln 2 1 2 3 4 1,-1,1,-1,… (define alternate (cons-stream 1 (stream-map - alternate))) 1/1,-1/2,1/3,… (define ln2-series (stream-map / alternate integers)) 35 Approximating the natural logarithm of 2 1 1 1 ln 2 1 2 3 4 (define ln2 (partial-sums ln2-series)) 1,1/2,5/6,7/12,… using Euler’s sequence acceleration (define ln2-euler (euler-transform ln2)) 7/10,29/42,25/36,457/660,… using super acceleration (define ln2-accelerated (accelerated-sequence euler-transform ln2)) 1,7/10,165/238,380522285/548976276,… 36 Power series 2 3 4 5 x x x x e 1 x 2 3 2 4 3 2 5 4 3 2 x 2 4 x x cos x 1 2 4 3 2 x3 x5 sin x x 3 2 5 4 3 2 37 Power series The series a0 a1 x a2 x 2 a3 x 3 is represented as the stream whose elements are the coefficient a0,a1,a2,a3… 38 Power series integral The integral of the series a0 a1 x a2 x 2 a3 x 3 is the series 1 1 1 2 3 c a0 x a1 x a2 x a3 x 4 2 3 4 where c is any constant 39 Power series integral Input: a0 , a1 , a2 , a3 , representing a power series 1 1 1 Output: a0 , a1 , a2 , a3 , coefficients of the 2 3 4 non-constant term of the integral of the series (define (integrate-series a) (stream-map / a integers)) 40 Exponent series x The function x e is its own derivative e x and the integral of e x are the same except for the constant term e 0 1 According to this rule, a definition of the exponent series is: (define exp-series (cons-stream 1 (integrate-series exp-series))) which results in 1,1,1/2,1/6,1/24,1/120… as expected e x 1 x x 2 x3 x 4 x5 2 3 2 4 3 2 5 4 3 2 41 Sine and cosine series The derivate of sine is cosine The derivate of cosine is (- sine) (define cosine-series (cons-stream 1 (stream-map – (integrate-series sine-series)))) (define sine-series (cons-stream 0 (integrate-series cosine-series))) Which results in cosine-series: 1,0,-1/2,0,1/24,… sine-series: 0,1,0,-1/6,0,1/120,… As expected x2 x4 cos x 1 2 4 3 2 x3 x5 sin x x 42 3 2 5 4 3 2 Repeat Input: procedure f of one argument, number of repetitions Output: f*…*f, n times (define (repeated f n) (if (= n 1) f (compose f (repeated f (- n 1))))) (define (compose f g) (lambda (x) (f (g x)))) 43 Repeat stream f,f*f,f*f*f,… = repeat = f,compose f,f,f,… with repeat (define f-series (cons-stream f f-series)) (define stream-repeat (cons-stream f (stream-map compose f-series stream-repeat))) We would like f to be a parameter 44 Repeat stream f,f*f,f*f*f,… = repeat = f,compose f,f,f,… with repeat (define (repeated f) (define f-series (cons-stream f f-series)) (define stream-repeat (cons-stream f (stream-map compose f-series stream-repeat))) stream-repeat) 45 Interleave 1,1,1,2,1,3,1,4,1,5,1,6,… (interleave ones integers) s0,t0,s1,t1,s2,t2,… interleave = s0,interleave (t, s from 2nd position) (define (interleave s t) (if (stream-null? s) t (cons-stream (stream-car s) (interleave t (stream-cdr s))))) 46