Lecture #14, Nov. 10, 2004

28
Cse536 Functional Programming Lecture #14, Nov. 10, 2004 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

Lecture #14, Nov. 10, 2004. 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 - PowerPoint PPT Presentation

Transcript of Lecture #14, Nov. 10, 2004

Page 1: Lecture  #14, Nov. 10, 2004

Cse536 Functional Programming

Lecture #14, Nov. 10, 2004

• 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: Lecture  #14, Nov. 10, 2004

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: Lecture  #14, Nov. 10, 2004

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: Lecture  #14, Nov. 10, 2004

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: Lecture  #14, Nov. 10, 2004

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: Lecture  #14, Nov. 10, 2004

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: Lecture  #14, Nov. 10, 2004

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: Lecture  #14, Nov. 10, 2004

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: Lecture  #14, Nov. 10, 2004

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: Lecture  #14, Nov. 10, 2004

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: Lecture  #14, Nov. 10, 2004

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: Lecture  #14, Nov. 10, 2004

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: Lecture  #14, Nov. 10, 2004

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: Lecture  #14, Nov. 10, 2004

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: Lecture  #14, Nov. 10, 2004

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: Lecture  #14, Nov. 10, 2004

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: Lecture  #14, Nov. 10, 2004

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: Lecture  #14, Nov. 10, 2004

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: Lecture  #14, Nov. 10, 2004

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: Lecture  #14, Nov. 10, 2004

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: Lecture  #14, Nov. 10, 2004

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: Lecture  #14, Nov. 10, 2004

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: Lecture  #14, Nov. 10, 2004

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: Lecture  #14, Nov. 10, 2004

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: Lecture  #14, Nov. 10, 2004

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: Lecture  #14, Nov. 10, 2004

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: Lecture  #14, Nov. 10, 2004

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: Lecture  #14, Nov. 10, 2004

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)