Lecture 14 nov 10 2004
Download
1 / 28

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


  • 97 Views
  • Uploaded on

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

loader
I am the owner, or an agent authorized to act on behalf of the owner, of the copyrighted work described.
capcha
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
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
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
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
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
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
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
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
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
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
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


Example stream diagram

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


Memo1

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


ad