|
@@ -0,0 +1,276 @@
|
|
|
+* Lecture 6A: Streams, Pt 1
|
|
|
+https://youtu.be/JkGKLILLy0I
|
|
|
+aside: good to see harry again -- feel like it's been a while
|
|
|
+
|
|
|
+
|
|
|
+"last time, gerry really let the cat out of the bag" with
|
|
|
+
|
|
|
+ /A S S I G N M E N T/
|
|
|
+
|
|
|
+ /S T A T E/
|
|
|
+
|
|
|
+ /C H A N G E/
|
|
|
+
|
|
|
+(F X) might have a side effect
|
|
|
+(F X) again might have a different value
|
|
|
+
|
|
|
+ /T I M E/
|
|
|
+
|
|
|
+ /I D E N T I T Y/
|
|
|
+
|
|
|
+ /S H A R I N G/
|
|
|
+
|
|
|
+the environment model is a far cry from the substitution model.
|
|
|
+we can no longer think about it like mathematics.
|
|
|
+it's philosophically harder.
|
|
|
+
|
|
|
+why did we get into this mess? to build modular systems.
|
|
|
+
|
|
|
+we'd like to build in the computer systems that fall into pieces in a
|
|
|
+way that mirrors reality.
|
|
|
+
|
|
|
+the reason building systems like this is hard has nothing to do with
|
|
|
+computers.
|
|
|
+
|
|
|
+the real reason we have these problems is with the way we view
|
|
|
+reality.
|
|
|
+
|
|
|
+time is an illusion and nothing ever changes.
|
|
|
+
|
|
|
+lets try some *stream processing*
|
|
|
+
|
|
|
+a couple example procedures:
|
|
|
+
|
|
|
+#+BEGIN_SRC scheme
|
|
|
+ (define (sum-odd-squares tree)
|
|
|
+ (if (leaf-node? tree)
|
|
|
+ (if (odd? tree)
|
|
|
+ (square tree)
|
|
|
+ 0)
|
|
|
+ (+ (sum-odd-squares
|
|
|
+ (left-branch tree))
|
|
|
+ (sum-odd-squares
|
|
|
+ (right-branch tree)))))
|
|
|
+#+END_SRC
|
|
|
+
|
|
|
+#+BEGIN_SRC scheme
|
|
|
+ (define (odd-fibs n)
|
|
|
+ (define (next k)
|
|
|
+ (if (> k n)
|
|
|
+ '()
|
|
|
+ (let ((f (fib k)))
|
|
|
+ (if (odd? f)
|
|
|
+ (cons f (next (1+ k)))
|
|
|
+ (next (1+ k))))))
|
|
|
+ (next 1))
|
|
|
+#+END_SRC
|
|
|
+
|
|
|
+these two procedures look very different, but really they are rather
|
|
|
+doing the same thing.
|
|
|
+
|
|
|
+ enumerate the leaves --> filter odd? --> map square --> accumulate
|
|
|
+ of a tree add from 0
|
|
|
+
|
|
|
+ enumerate interval --> map fibbonacci --> filter odd? --> accumulate
|
|
|
+ 1 to n cons from '()
|
|
|
+
|
|
|
+these natural steps don't appear in the two procedures because we
|
|
|
+don't have a good language for talking about them.
|
|
|
+
|
|
|
+let's build an appropriate language.
|
|
|
+
|
|
|
+ /S T R E A M S/
|
|
|
+
|
|
|
+a stream is a data abstraction, like anything else.
|
|
|
+
|
|
|
+: (cons-stream x y)
|
|
|
+: (head s)
|
|
|
+: (tail s)
|
|
|
+
|
|
|
+ for any x y
|
|
|
+: (head (cons-stream x y)) ;; x
|
|
|
+: (tail (cons-stream x y)) ;; y
|
|
|
+
|
|
|
+"the empty stream", like the empty list
|
|
|
+
|
|
|
+#+BEGIN_SRC scheme
|
|
|
+ (define (map-stream proc s)
|
|
|
+ (if (empty-stream? s)
|
|
|
+ the-empty-stream
|
|
|
+ (cons-stream
|
|
|
+ (proc (head s))
|
|
|
+ (map-stream proc (tail s)))))
|
|
|
+ (define (filter pred s)
|
|
|
+ (cond
|
|
|
+ ((empty-stream? s) the-empty-stream)
|
|
|
+ ((pred (head s))
|
|
|
+ (cons-stream (head s)
|
|
|
+ (filter pred
|
|
|
+ (tail s))))
|
|
|
+ (else (filter pred (tail s)))))
|
|
|
+ ;; etc as notated in the book
|
|
|
+#+END_SRC
|
|
|
+
|
|
|
+with those stream primitives,
|
|
|
+#+BEGIN_SRC scheme
|
|
|
+ (define (sum-odd-squares tree)
|
|
|
+ (accumulate
|
|
|
+ +
|
|
|
+ 0
|
|
|
+ (map
|
|
|
+ square
|
|
|
+ (filter odd
|
|
|
+ (enumerate-tree tree)))))
|
|
|
+ (define (odd-fibs n)
|
|
|
+ (accumulate
|
|
|
+ cons
|
|
|
+ '()
|
|
|
+ (filter
|
|
|
+ odd
|
|
|
+ (map fib (enum-interval 1 n)))))
|
|
|
+#+END_SRC
|
|
|
+
|
|
|
+we are establishing a CONVENTIONAL INTERFACE that allows us to glue
|
|
|
+things together.
|
|
|
+
|
|
|
+--> break
|
|
|
+
|
|
|
+here are some more complicated examples
|
|
|
+
|
|
|
+{{1 2 3 ...} {18 28 38 ...} ...}
|
|
|
+
|
|
|
+with flatten, get contents of stream of streams
|
|
|
+
|
|
|
+#+BEGIN_SRC scheme
|
|
|
+ (define (flatten st-of-st)
|
|
|
+ (accumulate append-streams
|
|
|
+ the-empty-stream
|
|
|
+ st-of-st))
|
|
|
+ (define (flatmap func stream)
|
|
|
+ (flatten (map func stream)))
|
|
|
+#+END_SRC
|
|
|
+
|
|
|
+GIVEN N, find all pairs of 0 < j < i ≤ n
|
|
|
+ such that i + j is prime
|
|
|
+
|
|
|
+eg for N=6:
|
|
|
+
|
|
|
+ | i | j | i+j |
|
|
|
+ |---+---+-----|
|
|
|
+ | 2 | 1 | 3 |
|
|
|
+ | 3 | 2 | 5 |
|
|
|
+ | 4 | 1 | 5 |
|
|
|
+
|
|
|
+
|
|
|
+#+BEGIN_SRC scheme
|
|
|
+ (flatmap
|
|
|
+ (lambda (i)
|
|
|
+ (map
|
|
|
+ (lambda (j) (list i j))
|
|
|
+ (enum-interval 1 (-1+ i))))
|
|
|
+ (enum-interval 1 n))
|
|
|
+
|
|
|
+ (filter
|
|
|
+ (lambda (p)
|
|
|
+ (prime? (+ (car p) (cadr p))))
|
|
|
+ (flatmap ...))
|
|
|
+
|
|
|
+ (define (prime-sum-pairs n)
|
|
|
+ (map
|
|
|
+ (lambda (p)
|
|
|
+ (list (car p)
|
|
|
+ (cadr p)
|
|
|
+ (+ (car p) (cadr p))))
|
|
|
+ (filter ...)))
|
|
|
+#+END_SRC
|
|
|
+
|
|
|
+there is a lot of power in flatmaps of flatmaps of maps etc ...
|
|
|
+this is how you can do nested-loop type shit
|
|
|
+
|
|
|
+writing flatmaps of flatmaps ... is not fun, so we have the syntactic
|
|
|
+sugar 'collect'
|
|
|
+
|
|
|
+#+BEGIN_SRC scheme
|
|
|
+ (define (prime-sum-pairs n)
|
|
|
+ (collect
|
|
|
+ (list i j (+ i j))
|
|
|
+ ((i (enum-interval 1 n))
|
|
|
+ (j (enum-interval 1 (-1+ i))))
|
|
|
+ (prime? (+ i j)))
|
|
|
+#+END_SRC
|
|
|
+
|
|
|
+we can solve the 8 queens problem
|
|
|
+: (safe? row col rest-of-positions) ;; is it safe to put a queen here?
|
|
|
+
|
|
|
+the traditional way to solve this is with a method called backtracking
|
|
|
+
|
|
|
+walk up and down the tree, but this is "too concerned with time"
|
|
|
+
|
|
|
+#+BEGIN_SRC scheme
|
|
|
+ (define (queens size)
|
|
|
+ (define (fill-cols k)
|
|
|
+ (if
|
|
|
+ (= k 0)
|
|
|
+ (singleton empty-board)
|
|
|
+ (collect (adjoin-position try-row
|
|
|
+ k
|
|
|
+ rest-queens)
|
|
|
+ ((rest-queens (fill-cols (-1+ k)))
|
|
|
+ (try-row (enum-interval 1 size)))
|
|
|
+ (safe? try-row k rest-queens)
|
|
|
+ )))
|
|
|
+ (fill-cols size))
|
|
|
+#+END_SRC
|
|
|
+
|
|
|
+every time harry says "fill-cols" i hear "phil collins" lol
|
|
|
+
|
|
|
+--> break
|
|
|
+
|
|
|
+the weakness of "traditional" lookin programs (sans the streams) is
|
|
|
+that they are "mixed up" -- the filtering and enumerating and
|
|
|
+collecting is all intertwined.
|
|
|
+
|
|
|
+this exact feature is also it's strength in efficiency.
|
|
|
+
|
|
|
+we can have our cake and eat it too, by using these streams and giving
|
|
|
+them the efficiency of traditional techniques. this power comes from
|
|
|
+the fact that streams are not lists.
|
|
|
+
|
|
|
+there's a lot of tuggin goin on lol
|
|
|
+
|
|
|
+we need to implement on "on demand" data structure
|
|
|
+(like a python generator)
|
|
|
+
|
|
|
+: cons-stream
|
|
|
+: head
|
|
|
+: tail
|
|
|
+
|
|
|
+: (cons-stream x y)
|
|
|
+is an abbreviation for
|
|
|
+: (cons x (delay y))
|
|
|
+, a promise
|
|
|
+
|
|
|
+: (head s) --> (car s)
|
|
|
+: (tail s) --> (force (cdr s))
|
|
|
+force calls in the promise
|
|
|
+
|
|
|
+: (delay exp)
|
|
|
+is an abbreviation for
|
|
|
+: (λ () exp)
|
|
|
+
|
|
|
+: (force p)
|
|
|
+is just
|
|
|
+: (p)
|
|
|
+
|
|
|
+delay decouples the apparent order of events from the real order in
|
|
|
+the machine
|
|
|
+
|
|
|
+: (define (delay ex)
|
|
|
+: (memo-proc
|
|
|
+: (λ () ex)))
|
|
|
+
|
|
|
+memo-proc saves previous computations
|
|
|
+
|
|
|
+this great power comes from the lack of distinction between data and
|
|
|
+procedures. we've written data structures that are rather like
|
|
|
+procedures. that's what streams are.
|