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
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
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
•
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.
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
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)
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
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))
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
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
server :: [Request] -> [Response]server xs = map (+1) xs
reqs = client respsresps = server reqs
Typical.A set of mutually
recursive equations
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
• 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
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
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
• But we can’t proceed since we can’t identify tf with tail(fibsFn()). Further unfolding becomes exponential.
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.
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]
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 :
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 .