Download Presentation
Lecture #14, Nov. 10, 2004

Loading in 2 Seconds...

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

I am the owner, or an agent authorized to act on behalf of the owner, of the copyrighted work described.
Download Presentation

## PowerPoint Slideshow about 'Lecture #14, Nov. 10, 2004' - francine-richard

An Image/Link below is provided (as is) to download presentation

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

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)

= 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

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

add

[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

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.

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)