260 likes | 333 Views
Streams Contract is the same as pairs... (head (pair-stream x str)) = x (tail (pair-stream x str)) = str ...but order of evaluation is different (pair-stream x str) evaluates x immediately, delays evaluation of str (tail str) forces evaluation of the tail.
E N D
Streams Contract is the same as pairs... (head (pair-stream x str)) = x (tail (pair-stream x str)) = str ...but order of evaluation is different (pair-stream x str) evaluates x immediately, delays evaluation of str (tail str) forces evaluation of the tail
Lazy Evaluation compute values only when needed implement with special form delay (delay expr) make a promise to evaluate expr when forced to (force delayed-expr) collect on the promise
An infinite stream (1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 ... (define (ones <stream>) (pair-stream 1 ones)) Compare (define (ones <list>) (pair 1 ones)) ==> ???
An infinite stream (1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 ... (define (ones <stream>) (pair-stream 1 ones)) Compare (define (ones <list>) (pair 1 ones)) ==> error: unbound identifier ones
(pair-stream 1 ones) =macro expansion=> (make <pair-stream> head-stream: 1 tail-stream: (delay ones)) =macro expansion=> (make <pair-stream> head-stream: 1 tail-stream: (method () ones)) ==> (1 . {proc () ones})
(head ones) ==> (head-stream ones) ==> 1 (tail ones) ==> (force (tail-stream ones)) ==> (force {proc () ones}) ==> ({proc () ones}) ==> ones ==> (1 . {proc () ones}) so ones is its own tail
Natural numbers (define integers-from (method ((n <integer>)) (pair-stream n (integers-from (inc n))))) (integers-from 42) is the infinite stream (42 43 44 45 46 47 48 49 50 51 52 ... (define (naturals <stream>) (integers-from 0)) naturals is the infinite stream (0 1 2 3 4 5 6 7 8 9 10 11 12 13 ...
(add-method filter (method ((test <boolean>) (s <stream>)) (cond ((empty? s) empty-stream) ((test (head s)) (pair-stream (head s) (filter test (tail s)))) (else: (filter test (tail s)))))) (define (divisible? <function>) (method ((x <integer>) (n <integer>)) (zero? (modulo x n)))) (define (divisible-by-3? <function>) (method ((x <integer>)) (divisible? x 3))) (define (threes <stream>) (filter divisible-by-3? naturals)) this is the infinite stream (0 3 6 9 12 15 ...
(define (print-stream <function>) (method ((s <stream>)) (print (head s)) (print-stream (tail s)))) (print-stream naturals) What does (print-stream naturals) do? Print 0, force the tail (integers-from (inc 0)) evaluate (inc 0) ==> 1 evaluate integers-from ==> (1 . {proc () (integers-from (inc 1))}) Print 1, force the tail... (2 . {promise (integers-from (inc 2))}) Print 2, force the tail... (3 . {promise (integers-from (inc 3))}) Print 3, force the tail...
Sieve of Eratosthenes (300 BC) • 2 is prime • a number n > 2 is prime iff • it is not divisible by any smaller prime
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 ...
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 ...
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 ...
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 ...
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 ...
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 ...
(define (sieve <function>) (method ((s <stream>)) (bind ((next-prime (head s))) ;head is prime (pair-stream next-prime (sieve ;recursively sieve tail after (filter ;removing all multiples of head (method ((x <integer>)) (not (divisible? x next-prime))) (tail s))))))) (define (primes <stream>) (sieve (integers-from 2))) (print-stream primes) 2 3 5 7 11 13 17 19 23 ...
Componentwise addition of streams (define (add-streams <function>) (method ((a <stream>) (b <stream>)) (cond ((empty-stream? a) b) ((empty-stream? b) a) (else: (pair-stream (+ (head a) (head b)) (add-streams (tail a) (tail b))))))) (add-streams (a0 a1 a2 a3 ...) (b0 b1 b2 b3...)) ==> (a0+b0 a1+b1 a2+b2 a3+b3 ...)
Natural numbers revisited (define (naturals <stream>) (pair-stream 0 (add-streams ones naturals))) naturals = (0 1 2 3 4 5 6 7 8 9 10 11 12 ... ones = (1 1 1 1 1 1 1 1 1 1 1 1 1 ... sum = (1 2 3 4 5 6 7 8 9 10 11 12 13 ... Pair 0 onto the front and we get naturals back: (0 1 2 3 4 5 6 7 8 9 10 11 12 13 ...
Fibonacci numbers F(0) = 0 F(1) = 1 F(n) = F(n-1) + F(n-2) for n 2 (define (fibs <stream>) (pair-stream 0 (pair-stream 1 (add-streams fibs (tail fibs))))) fibs = (0 1 1 2 3 5 8 13 21 34 ... (tail fibs) = (1 1 2 3 5 8 13 21 34 55 ... sum = (1 2 3 5 8 13 21 34 55 89 ... Pair 0 and 1 onto the front and we get fibs back: fibs = (0 1 1 2 3 5 8 13 21 34 55 89 ...
A more efficient version (define (fibs-from <function>) (method ((a <integer>) (b <integer>)) (pair-stream a (fibs-from b (+ a b))))) (define (efficient-fibs <stream>) (fibs-from 0 1)) this version: O(n) to create the first n fibs last version: O(p^n) where p = (1+sqrt(5))/2
Divergent computations It’s possible to create streams with nothing in them that are not the empty stream— even worse, empty? can't detect them! (define (lose <stream>) (filter odd? (filter even? naturals)))
Merge — merge two streams into one Example: joint bank account Dexter stream: 1/1/98 23:59 deposit $500 1/15/98 23:59 deposit $500 2/1/98 23:59 deposit $500 2/15/98 23:59 deposit $500 ... Fran stream: 1/3/98 10:36 withdraw $200 1/7/98 14:15 withdraw $150 1/10/98 15:44 withdraw $500 1/19/98 9:05 withdraw $825 ...
Dexter merge account balances Fran Merge by date & time so that all transactions on the output stream are in the right order
(1 3 6 12 17 18 20 ... (2 5 9 10 19 22 31 ... merge (1 2 3 5 6 9 10 12 17 18 19 20 ...
(define (merge <function>) (method ((s1 <stream>) (s2 <stream>)) (cond ((empty? s1) s2) ((empty? s2) s1) ((< (head s1) (head s2)) (pair-stream (head s1) (merge (tail s1) s2))) (else: (pair-stream (head s2) (merge s1 (tail s2)))))))