Programming with Streams Infinite lists v.s. Streams Normal order evaluation Recursive streams

28
Cse536 Functional Programming ?? Programming with Streams 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

description

??. Programming with Streams 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. - PowerPoint PPT Presentation

Transcript of Programming with Streams Infinite lists v.s. Streams Normal order evaluation Recursive streams

Page 1: Programming with Streams Infinite lists v.s. Streams Normal order evaluation Recursive streams

Cse536 Functional Programming

??

• Programming with Streams– 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

Page 2: Programming with Streams Infinite lists v.s. Streams Normal order evaluation Recursive streams

Cse536 Functional Programming

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.

Page 3: Programming with Streams Infinite lists v.s. Streams Normal order evaluation Recursive streams

Cse536 Functional Programming

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 for bot

Page 4: Programming with Streams Infinite lists v.s. Streams Normal order evaluation Recursive streams

Cse536 Functional Programming

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)

Page 5: Programming with Streams Infinite lists v.s. Streams Normal order evaluation Recursive streams

Cse536 Functional Programming

Normal order continued

• Letlet x = y + 2

z = x / 0

in if x=0 then z else w

• Wheref w = if x=0 then z else w

where x = y + 2

z = x / 0

• Case exp’s– case f x of [] -> a ; (y:ys) -> b

Page 6: Programming with Streams Infinite lists v.s. Streams Normal order evaluation Recursive streams

Cse536 Functional Programming

Recursive streams

fibA 0 = 1

fibA 1 = 1

fibA n = fibA(n-1) + fibA(n-2)

• Unfold this a few timesfibA 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))

Page 7: Programming with Streams Infinite lists v.s. Streams Normal order evaluation Recursive streams

Cse536 Functional Programming

Fibonacci Stream

fibs :: [ Integer ]

fibs = 1 : 1 : (zipWith (+) fibs (tail fibs))

This is much faster! And uses less resources. Why?

1 1 2 3 5 8 13 21 … fibonacci sequence

+ 1 2 3 5 8 13 21 34 … tail of fibonacci sequence

2 3 5 8 13 21 34 55 …tail of tail of fibonacci sequence

Page 8: Programming with Streams Infinite lists v.s. Streams Normal order evaluation Recursive streams

Cse536 Functional Programming

Abstract on tail of fibsfibs = 1 : 1 : (add fibs (tail fibs)) = 1 : tf where tf = 1 : add fibs (tail fibs) = 1 : tf where tf = 1 : add fibs tf

Abstract on tail of tf = 1 : tf where tf = 1 : tf2 tf2 = add fibs tf

Unfold add = 1 : tf where tf = 1 : tf2 tf2 = 2 : add tf tf2

Add x y =zipWith (+) x y

Page 9: Programming with Streams Infinite lists v.s. Streams Normal order evaluation Recursive streams

Cse536 Functional Programming

Abstract and unfold again

fibs = 1 : tf where tf = 1 : tf2 tf2 = 2 : add tf tf2 = 1 : tf where tf = 1 : tf2 tf2 = 2 : tf3 tf3 = add tf tf2 = 1 : tf where tf = 1 : tf2 tf2 = 2 : tf3 tf3 = 3 : add tf2 tf3tf is used only once, so eliminate = 1 : 1 : tf2 where tf2 = 2 : tf3 tf3 = 3 : add tf2 tf3

Page 10: Programming with Streams Infinite lists v.s. Streams Normal order evaluation Recursive streams

Cse536 Functional Programming

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

Page 11: Programming with Streams Infinite lists v.s. Streams Normal order evaluation Recursive streams

Cse536 Functional Programming

Stream Diagrams

(:)

(:)

add

fibs = [1,1,2,3,5,8,…]

[1,2,3,5,8, …]1

1 [2,3,5,8,…]

• Streams are “wires” along which values flow.

• Boxes and circles takewires as input and produce values for new wires asoutput.

•Forks in a wire send theirvalues to both destinations

•A stream diagram correspondsto a Haskell function (usuallyrecursive)

Page 12: Programming with Streams Infinite lists v.s. Streams Normal order evaluation Recursive streams

Cse536 Functional Programming

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

inp

out+1 next

Page 13: Programming with Streams Infinite lists v.s. Streams Normal order evaluation Recursive streams

Cse536 Functional Programming

Example counter :: [ Bool ] -> [ Int ]

counter inp = out

where

out = if* inp then* 0 else* next

next = [0] followedBy map (+ 1) out

[0]if*

0F...

0...+10...

1...

outnext

Page 14: Programming with Streams Infinite lists v.s. Streams Normal order evaluation Recursive streams

Cse536 Functional Programming

Example

counter :: [ Bool ] -> [ Int ]

counter inp = out

where

out = if* inp then* 0 else* next

next = [0] followedBy map (+ 1) out

[0]if*

0F:F..

0:1..+10:1..

1:2..

outnext

Page 15: Programming with Streams Infinite lists v.s. Streams Normal order evaluation Recursive streams

Cse536 Functional Programming

Example

counter :: [ Bool ] -> [ Int ]

counter inp = out

where

out = if* inp then* 0 else* next

next = [0] followedBy map (+ 1) out

[0]if*

0F:F:T..

0:1:0..+10:1:2

1:2:1..

outnext

Page 16: Programming with Streams Infinite lists v.s. Streams Normal order evaluation Recursive streams

Cse536 Functional Programming

Client, Server Example

type Response = Integertype Request = Integer

client :: [Response] -> [Request]client ys = 1 : ys

server :: [Request] -> [Response]server xs = map (+1) xs

reqs = client respsresps = server reqs

Typical.A set of mutually

recursive equations

Page 17: Programming with Streams Infinite lists v.s. Streams Normal order evaluation Recursive streams

Cse536 Functional Programming

reqs = client resps = 1 : resps = 1 : server reqsAbstract on (tail reqs) = 1 : tr where tr = server reqsUse definition of server = 1 : tr where tr = 2 : server reqsabstract = 1 : tr where tr = 2 : tr2 tr2 = server reqsSince tr is used only once= 1 : 2 : tr2 where tr2 = server reqsRepeat as required

client ys = 1 : ysserver xs = map (+1) xsreqs = client respsresps = server reqs

Page 18: Programming with Streams Infinite lists v.s. Streams Normal order evaluation Recursive streams

Cse536 Functional Programming

Lazy Patterns

• Suppose client wants to test servers responses.clientB (y : ys) = if ok y then 1 :(y:ys) else error "faulty server" where ok x = Trueserver 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

Page 19: Programming with Streams Infinite lists v.s. Streams Normal order evaluation Recursive streams

Cse536 Functional Programming

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

Page 20: Programming with Streams Infinite lists v.s. Streams Normal order evaluation Recursive streams

Cse536 Functional Programming

Solution 2 – lazy patterns

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 where (y:ys) = resps = 1 : resps

In Haskell the ~ before a pattern makes it lazy

Page 21: Programming with Streams Infinite lists v.s. Streams Normal order evaluation Recursive streams

Cse536 Functional Programming

MemoizationfibsFn :: () -> [ 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.

Page 22: Programming with Streams Infinite lists v.s. Streams Normal order evaluation Recursive streams

Cse536 Functional Programming

memo1

• We need a function that builds a table of previous calls.

• Memo : (a -> b) -> (a -> b)

1 12 23 3

10

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.

Page 23: Programming with Streams Infinite lists v.s. Streams Normal order evaluation Recursive streams

Cse536 Functional Programming

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]

Page 24: Programming with Streams Infinite lists v.s. Streams Normal order evaluation Recursive streams

Cse536 Functional Programming

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 is the error or non-terminating computation.

Think of as an approximation to an answer. We can get more precise approximations by: ones = 1 : ones

1 : 1 : 1 : 1 : 1 : 1 :

Page 25: Programming with Streams Infinite lists v.s. Streams Normal order evaluation Recursive streams

Cse536 Functional Programming

Proof by induction

• To do a proof about infinite lists, do a proof by induction where the base case is , rather than [] since an infinite list does not have a [] case (because its infinite).– 1) Prove P{}– 2) Assume P{xs} is true then prove P{x:xs}

• Auxiliary rule:– Pattern match against returns .

• I.e. case z of { [] -> e; y:ys -> f }

Page 26: Programming with Streams Infinite lists v.s. Streams Normal order evaluation Recursive streams

Cse536 Functional Programming

Example

• Prove: P{x} ==

(x ++ y) ++ w = x ++ (y++w)

1) Prove P{}( ++ y) ++ w = ++ (y++w)

2) Assume P{xs} (xs ++ y) ++ w = xs ++ (y++w)

Prove P{x:xs} (x:xs ++ y) ++ w = x:xs ++ (y++w)

Page 27: Programming with Streams Infinite lists v.s. Streams Normal order evaluation Recursive streams

Cse536 Functional Programming

Base Case

( ++ y) ++ w = ++ (y++w)

( ++ y) ++ w • pattern match in def of ++

++ w• pattern match in def of ++

• pattern match in def of ++

++ (y++w)

Page 28: Programming with Streams Infinite lists v.s. Streams Normal order evaluation Recursive streams

Cse536 Functional Programming

Induction step

1) Assume P{xs} (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• Def of (++)x :((xs ++ y) ++ w)• Induction hypothesisx : (xs ++ (y ++ w))• Def of (++)(x:xs) ++ (y ++ w)