Presentation is loading. Please wait.

Presentation is loading. Please wait.

?? Programming with Streams Reading assignment

Similar presentations


Presentation on theme: "?? Programming with Streams Reading assignment"— Presentation transcript:

1 ?? Programming with Streams Reading assignment
Infinite lists v.s. Streams Normal order evaluation Recursive streams Stream Diagrams Lazy patterns memoization Inductive properties of infinite lists Reading assignment Chapter 14. Programming with Streams Chapter 15. A module of reactive animations

2 Infinite lists v.s. Streams
data Stream a = a :^ Stream a A stream is an infinite list. It is never empty We could define a stream in Haskell as written above. But we prefer to use lists. This way we get to reuse all the polymorphic functions on lists.

3 Infinite lists and bottom
twos = 2 : twos twos = 2 : (2 : twos) twos = 2 : (2 : (2 : twos)) twos = 2 : (2 : (2 : (2 : twos))) bot :: a bot = bot What is the difference between twos and bot ? Sometimes we write z for bot

4 Normal Order evaluation
Why does head(twos) work? Head (2 : twos) Head(2 : (2 : twos)) Head (2: (2 : (2 : twos))) The outermost – leftmost rule. Outermost Use the body of the function before its arguments Leftmost Use leftmost terms: (K 4) (5 + 2) Be careful with Infix: (m + 2) `get` (x:xs)

5 Normal order continued
Let let x = y + 2 z = x / 0 in if x=0 then z else w Where f w = if x=0 then z else w where x = y + 2 Case exp’s case f x of [] -> a ; (y:ys) -> b

6 Recursive streams Unfold this a few times fibA 0 = 1 fibA 1 = 1
fibA n = fibA(n-1) + fibA(n-2) Unfold this a few times fibA 8 = fibA 7 + fibA 6 = (fibA 6 + fibA 5) + (fibA 5 + fibA 4) = ((fibA 5 + fibA 4) + (fibA 4 + fibA 3)) +((fibA 4 + fibA 3) + (fibA 3 + fibA 2))

7 Fibonacci Stream This is much faster! And uses less resources. Why?
… fibonacci sequence … tail of fibonacci sequence …tail of tail of fibonacci sequence fibs :: [ Integer ] fibs = 1 : 1 : (zipWith (+) fibs (tail fibs)) This is much faster! And uses less resources. Why?

8 Abstract on tail of fibs fibs = 1 : 1 : (add fibs (tail fibs))
Add x y = zipWith (+) x y Abstract on tail of fibs fibs = 1 : 1 : (add fibs (tail fibs)) = 1 : tf where tf = 1 : add fibs (tail fibs) where tf = 1 : add fibs tf Abstract on tail of tf where tf = 1 : tf2 tf2 = add fibs tf Unfold add tf2 = 2 : add tf tf2

9 Abstract and unfold again
fibs = 1 : tf where tf = 1 : tf2 tf2 = 2 : add tf tf2 = 1 : tf tf2 = 2 : tf3 tf3 = add tf tf2 tf3 = 3 : add tf2 tf3 tf is used only once, so eliminate = 1 : 1 : tf2 where tf2 = 2 : tf3

10 Again This can go on forever. But note how the sharing makes the inefficiencies of fibA go away. fibs = 1 : 1 : 2 : tf3 where tf3 = 3 : tf4 tf4 = 5 : add tf3 tf4 fibs = 1 : 1 : 2 : 3 : tf4 where tf4 = 5 : tf5 tf5 = 8 : add tf4 tf5

11 Stream Diagrams fibs = [1,1,2,3,5,8,…] (:) [1,2,3,5,8, …] 1 (:)
Streams are “wires” along which values flow. Boxes and circles take wires as input and produce values for new wires as output. Forks in a wire send their values to both destinations A stream diagram corresponds to a Haskell function (usually recursive) (:) [1,2,3,5,8, …] 1 (:) [2,3,5,8,…] 1 add

12 Example Stream Diagram
counter :: [ Bool ] -> [ Int ] counter inp = out where out = if* inp then* 0 else* next next = [0] followedBy map (+ 1) out [0] if* inp out +1 next

13 Example [0] +1 if* next out counter :: [ Bool ] -> [ Int ]
counter inp = out where out = if* inp then* 0 else* next next = [0] followedBy map (+ 1) out [0] if* F... 0... +1 1... out next

14 Example [0] +1 if* next out counter :: [ Bool ] -> [ Int ]
counter inp = out where out = if* inp then* 0 else* next next = [0] followedBy map (+ 1) out [0] if* F:F.. 0:1.. +1 1:2.. out next

15 Example [0] +1 if* next out counter :: [ Bool ] -> [ Int ]
counter inp = out where out = if* inp then* 0 else* next next = [0] followedBy map (+ 1) out [0] if* F:F:T.. 0:1:0.. +1 0:1:2 1:2:1.. out next

16 Client, Server Example type Response = Integer type Request = Integer
client :: [Response] -> [Request] client ys = 1 : ys server :: [Request] -> [Response] server xs = map (+1) xs reqs = client resps resps = server reqs Typical. A set of mutually recursive equations

17 Abstract on (tail reqs) = 1 : tr where tr = server reqs
client ys = 1 : ys server xs = map (+1) xs reqs = client resps resps = server reqs reqs = client resps = 1 : resps = 1 : server reqs Abstract on (tail reqs) = 1 : tr where tr = server reqs Use definition of server where tr = 2 : server reqs abstract where tr = 2 : tr2 tr2 = server reqs Since tr is used only once = 1 : 2 : tr2 where tr2 = server reqs Repeat as required

18 Lazy Patterns Now what happens . . . We can’t unfold
Suppose client wants to test servers responses. clientB (y : ys) = if ok y then 1 :(y:ys) else error "faulty server" where ok x = True server xs = map (+1) xs Now what happens . . . Reqs = client resps = client(server reqs) = client(server(client resps)) = client(server(client(server reqs)) We can’t unfold

19 Solution 1 Rewrite client
client ys = 1 : (if ok (head ys) then ys else error "faulty server") where ok x = True Pulling the (:) out of the if makes client immediately exhibit a cons cell Using (head ys) rather than the pattern (y:ys) makes the evaluation of ys lazy

20 Solution 2 – lazy patterns
In Haskell the ~ before a pattern makes it lazy client ~(y:ys) = 1 : (if ok y then y:ys else err) where ok x = True err = error "faulty server” Calculate using where clauses Reqs = client resps = 1 : (if ok y then y:ys else err) where (y:ys) = resps = 1 : y : ys = 1 : resps

21 Memoization Unfolding we get:
fibsFn :: () -> [ Integer ] fibsFn () = 1 : 1 : (zipWith (+) (fibsFn ()) (tail (fibsFn ()))) Unfolding we get: fibsFn () = 1:1: add (fibsFn()) (tail (fibsFn ())) = 1 : tf where tf = 1:add(fibsFn())(tail(fibsFn())) But we can’t proceed since we can’t identify tf with tail(fibsFn()). Further unfolding becomes exponential.

22 memo1 We need a function that builds a table of previous calls.
Memo : (a -> b) -> (a -> b) 1 2 3 4 5 Memo fib x = if x in_Table_at i then Table[i] else set_table(x,fib x); return fib x Memo1 builds a table with exactly 1 entry.

23 Using memo1 mfibsFn x = let mfibs = memo1 mfibsFn
in 1:1:zipWith(+)(mfibs())(tail(mfibs())) Main> take 20 (mfibsFn()) [1,1,2,3,5,8,13,21,34,55,89,144,233,377, 610,987,1597,2584,4181,6765]

24 Inductive properties of infinite lists
Which properties are true of infinite lists take n xs ++ drop n xs = xs reverse(reverse xs) = xs Recall that z is the error or non-terminating computation. Think of z as an approximation to an answer. We can get more precise approximations by: ones = 1 : ones z 1 : z 1 : 1 : z 1 : 1 : 1 : z

25 Proof by induction To do a proof about infinite lists, do a proof by induction where the base case is z, rather than [] since an infinite list does not have a [] case (because its infinite). 1) Prove P{z} 2) Assume P{xs} is true then prove P{x:xs} Auxiliary rule: Pattern match against z returns z. I.e. case z of { [] -> e; y:ys -> f }

26 Example Prove: P{x} == (x ++ y) ++ w = x ++ (y++w) Prove P{z}
(z ++ y) ++ w = z ++ (y++w) Assume P{xs} (xs ++ y) ++ w = xs ++ (y++w) Prove P{x:xs} (x:xs ++ y) ++ w = x:xs ++ (y++w)

27 Base Case (z ++ y) ++ w z ++ w z z ++ (y++w)
(z ++ y) ++ w = z ++ (y++w) (z ++ y) ++ w pattern match in def of ++ z ++ w z z ++ (y++w)

28 Induction step Assume P{xs} Prove P{x:xs} (x:xs ++ y) ++ w Def of (++)
(xs ++ y) ++ w = xs ++ (y++w) Prove P{x:xs} (x:xs ++ y) ++ w = x:xs ++ (y++w) (x:xs ++ y) ++ w Def of (++) (x:(xs ++ y)) ++ w x :((xs ++ y) ++ w) Induction hypothesis x : (xs ++ (y ++ w)) (x:xs) ++ (y ++ w)


Download ppt "?? Programming with Streams Reading assignment"

Similar presentations


Ads by Google