Loading in 5 sec....

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

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

Download Presentation

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

Loading in 2 Seconds...

- 110 Views
- Uploaded on
- Presentation posted in: General

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

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

- 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

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.

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

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

- 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

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

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

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

- 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

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

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

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

- 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

- 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

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

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

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

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]

- 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

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

- Pattern match against z returns z.

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

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

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