* Lecture 6B: Streams Pt. 2 https://youtu.be/qp05AtXbOP0 the key idea is that we decouple the apparent order of events in our programs from the actual order of events in the computer #+BEGIN_SRC scheme (define (nth-stream n s) (if (= n 0) (head s) (nth-stream (-1+ n) (tail s)))) #+END_SRC elements aren't calculated until they are forced elements are calculated when they are forced #+BEGIN_SRC scheme (define (integers-from n) (cons-stream n (integers-from (+ n 1)))) (define integers (integers-from 1)) (define (no-seven x) (not (= (remainder x 7) 0))) (define no-sevens (filter no-seven integers)) #+END_SRC /the sieve of eratosthenes/ for finding all primes #+BEGIN_SRC scheme (define (sieve s) (cons-stream (head s) (sieve (filter (lambda (x) (not (divisible? x (head s)))) (tail s))))) (define primes (sieve (integers-from 2))) #+END_SRC --> break there's another way to think about stream programming -- not operating on distinct elements, but streams as a whole #+BEGIN_SRC scheme (define (add-streams s1 s2) (cond ((empty-stream? s1) s2) ((empty-stream? s2) s1) (else (cons-stream (+ (head s1) (head s2)) (add-streams (tail s1) (tail s2)))))) (define (scale-stream c s) (map-stream (lambda (x) (* x c)) s)) #+END_SRC #+BEGIN_SRC scheme (define ones (cons-stream 1 ones)) ;; infinite stream of 1s (define ints (cons-stream 1 (add-streams ints ones))) #+END_SRC harry: this is very sneaky #+BEGIN_SRC scheme (define (integral s initial-value dt) (define int (cons-stream initial-value (add-streams (scale-stream dt s) int))) int) #+END_SRC #+BEGIN_SRC scheme (define fibs (cons-stream 0 (cons-stream 1 (add-streams fibs (tail fibs))))) #+END_SRC "this is like learning recursion again, but instead of recursive procedures, we have recursive data" "this shouldn't be surprising to you" as there is no difference between data and procedures #+BEGIN_SRC scheme (define y (integral dy 1 .001)) (define dy (map square y)) ;; this doesn't work ;; recursively defined #+END_SRC delayed integral: #+BEGIN_SRC scheme (define (integral delayed-s initial-value dt) (define int (cons-stream initial-value (let ((s (force delayed-s))) (add-streams (scale-stream dt s) int)))) int) #+END_SRC #+BEGIN_SRC scheme (define y (integral (delay dy) 1 .001)) (define dy (map square y)) ;; this does work ;; bc of delay #+END_SRC --> break "before the break, something nasty started to happen" the explicit use of delay is messy we could rewrite the language to attach a delay to every procedure it would be a "normal order" evaluation language vs what we've been using, "applicative order" instead of evaluating arguments, just provide promises, passing promises around until you reach a primitive applicative order carries a price: we are trying to abstract away time, but if we go too far, we lose expressiveness in favor of elegance we can no longer really express iterative procedures BUT there is another, more striking reason: normal order and side effects don't mix "it's very confusing for a very deep reason": we've thrown away time the debate over FUNCTIONAL PROGRAMMING a purely functional language has no side effects no assignment a bank acct w/o state: #+BEGIN_SRC scheme (define (make-deposit-account balance deposit-stream) (cons-stream balance (make-deposit-account (+ balance (head deposit-stream)) (tail deposit-stream)))) #+END_SRC "the poor ppl sitting at the bank account window have the misfortune to exist in time"