* 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"
