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

(define (nth-stream n s)
  (if (= n 0)
      (head s)
      (nth-stream (-1+ n) (tail s))))

elements aren't calculated until they are forced

elements are calculated when they are forced

(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))

the sieve of eratosthenes
for finding all primes

(define (sieve s)
  (cons-stream
   (head s)
   (sieve (filter
           (lambda (x)
             (not
              (divisible? x (head s))))
           (tail s)))))
(define primes
  (sieve (integers-from 2)))

–> break

there's another way to think about stream programming
– not operating on distinct elements, but streams as a whole

(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))
(define ones (cons-stream 1 ones)) ;; infinite stream of 1s
(define ints (cons-stream 1 (add-streams ints ones)))

harry: this is very sneaky

(define (integral s initial-value dt)
  (define int
    (cons-stream
     initial-value
     (add-streams (scale-stream dt s)
                  int)))
  int)
(define fibs
  (cons-stream 0
               (cons-stream 1
                            (add-streams fibs (tail fibs)))))

"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

(define y (integral dy 1 .001))
(define dy (map square y)) ;; this doesn't work
;; recursively defined

delayed integral:

(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)
(define y (integral (delay dy) 1 .001))
(define dy (map square y)) ;; this does work
;; bc of delay

–> 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:

(define (make-deposit-account
         balance deposit-stream)
  (cons-stream
   balance
   (make-deposit-account
    (+ balance (head deposit-stream))
    (tail deposit-stream))))

"the poor ppl sitting at the bank account window have the misfortune
to exist in time"

Author: jordyn

Created: 2021-02-15 Mon 16:10