Date post: | 02-Jan-2016 |
Category: |
Documents |
Upload: | jermaine-cherry |
View: | 47 times |
Download: | 5 times |
Cse536 Functional Programming
??
• 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
Unfold add = 1 : tf where tf = 1 : tf2 tf2 = 2 : add tf tf2
Add x y =zipWith (+) x y
Cse536 Functional Programming
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 tf3tf is used only once, so eliminate = 1 : 1 : tf2 where tf2 = 2 : tf3 tf3 = 3 : add tf2 tf3
Cse536 Functional Programming
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
Cse536 Functional Programming
Stream Diagrams
(:)
(:)
add
fibs = [1,1,2,3,5,8,…]
[1,2,3,5,8, …]1
1 [2,3,5,8,…]
• Streams are “wires” along which values flow.
• Boxes and circles takewires as input and produce values for new wires asoutput.
•Forks in a wire send theirvalues to both destinations
•A stream diagram correspondsto a Haskell function (usuallyrecursive)
Cse536 Functional Programming
Example Stream Diagram
counter :: [ Bool ] -> [ Int ]
counter inp = out
where
out = if* inp then* 0 else* next
next = [0] followedBy map (+ 1) out
[0] if*0
inp
out+1 next
Cse536 Functional Programming
Example counter :: [ Bool ] -> [ Int ]
counter inp = out
where
out = if* inp then* 0 else* next
next = [0] followedBy map (+ 1) out
[0]if*
0F...
0...+10...
1...
outnext
Cse536 Functional Programming
Example
counter :: [ Bool ] -> [ Int ]
counter inp = out
where
out = if* inp then* 0 else* next
next = [0] followedBy map (+ 1) out
[0]if*
0F:F..
0:1..+10:1..
1:2..
outnext
Cse536 Functional Programming
Example
counter :: [ Bool ] -> [ Int ]
counter inp = out
where
out = if* inp then* 0 else* next
next = [0] followedBy map (+ 1) out
[0]if*
0F:F:T..
0:1:0..+10:1:2
1:2:1..
outnext
Cse536 Functional Programming
Client, Server Example
type Response = Integertype Request = Integer
client :: [Response] -> [Request]client ys = 1 : ys
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
client ys = 1 : ysserver xs = map (+1) xsreqs = client respsresps = server reqs
Cse536 Functional Programming
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 = 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
In Haskell the ~ before a pattern makes it lazy
Cse536 Functional Programming
MemoizationfibsFn :: () -> [ 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.
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 .
• I.e. case z of { [] -> e; y:ys -> f }
Cse536 Functional Programming
Example
• Prove: P{x} ==
(x ++ y) ++ w = x ++ (y++w)
1) Prove P{}( ++ y) ++ w = ++ (y++w)
2) Assume P{xs} (xs ++ y) ++ w = xs ++ (y++w)
Prove P{x:xs} (x:xs ++ y) ++ w = x:xs ++ (y++w)
Cse536 Functional Programming
Base Case
( ++ y) ++ w = ++ (y++w)
( ++ y) ++ w • pattern match in def of ++
++ w• pattern match in def of ++
• pattern match in def of ++
++ (y++w)
Cse536 Functional Programming
Induction step
1) 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 hypothesisx : (xs ++ (y ++ w))• Def of (++)(x:xs) ++ (y ++ w)