This presentation is the property of its rightful owner.
1 / 28

# Lecture #14, Nov. 10, 2004 PowerPoint PPT Presentation

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

Lecture #14, Nov. 10, 2004

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.

- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -

### 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

• Chapter 14. Programming with Streams

• Chapter 15. A module of reactive animations

### 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.

### 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

### Normal Order evaluation

• 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)

### 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

z = x / 0

• Case exp’s

• case f x of [] -> a ; (y:ys) -> b

### Recursive streams

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))

### 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

zipWith (+) x y

Abstract on tail of fibs

fibs = 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

= 1 : tf

where tf = 1 : tf2

tf2 = 2 : add tf tf2

### 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

= 1 : tf

where tf = 1 : tf2

tf2 = 2 : tf3

tf3 = 3 : add tf2 tf3

tf is used only once, so eliminate

= 1 : 1 : tf2

where tf2 = 2 : tf3

tf3 = 3 : add tf2 tf3

### 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

### Stream Diagrams

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

• 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

[0]

+1

if*

next

out

0

inp

### Example Stream Diagram

counter :: [ Bool ] -> [ Int ]

counter inp = out

where

out = if* inp then* 0 else* next

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

1...

[0]

0...

+1

if*

0...

next

out

0

F...

Example

counter :: [ Bool ] -> [ Int ]

counter inp = out

where

out = if* inp then* 0 else* next

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

1:2..

[0]

0:1..

+1

if*

0:1..

next

out

0

F:F..

Example

counter :: [ Bool ] -> [ Int ]

counter inp = out

where

out = if* inp then* 0 else* next

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

1:2:1..

[0]

0:1:2

+1

if*

0:1:0..

next

out

0

F:F:T..

Example

counter :: [ Bool ] -> [ Int ]

counter inp = out

where

out = if* inp then* 0 else* next

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

### 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

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

= 1 : tr

where tr = 2 : server reqs

abstract

= 1 : tr

where tr = 2 : tr2

tr2 = server reqs

Since tr is used only once

= 1 : 2 : tr2

where tr2 = server reqs

Repeat as required

### 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 = 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

### 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

### 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

where (y:ys) = resps

= 1 : resps

### Memoization

fibsFn :: () -> [ Integer ]

fibsFn () = 1 : 1 :

(zipWith (+) (fibsFn ()) (tail (fibsFn ())))

• Unfolding we get:

fibsFn () = 1:1: add (fibsFn()) (tail (fibsFn ()))

= 1 : tf

• But we can’t proceed since we can’t identify tf with tail(fibsFn()). Further unfolding becomes exponential.

0

1

1

1

2

2

3

3

4

5

### memo1

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

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

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.

### 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]

### 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 ofz 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

### 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 }

### 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)

### Base Case

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

(z ++ y) ++ w

• pattern match in def of ++

z ++ w

• pattern match in def of ++

z

• pattern match in def of ++

z ++ (y++w)

### Induction step

• 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 hypothesis

x : (xs ++ (y ++ w))

• Def of (++)

(x:xs) ++ (y ++ w)