Download S14Streams

Survey
yes no Was this document useful for you?
   Thank you for your participation!

* Your assessment is very important for improving the work of artificial intelligence, which forms the content of this project

Document related concepts
no text concepts found
Transcript
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
twos
twos
twos
=
=
=
=
2
2
2
2
bot :: a
bot = bot
:
:
:
:
twos
(2 : twos)
(2 : (2 : twos))
(2 : (2 : (2 : twos)))
Sometimes we
write z for bot
• What is the difference between twos and 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
• 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
Cse536 Functional Programming
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))
Cse536 Functional Programming
Fibonacci Stream
1 1 2 3 5
+ 1 2 3 5 8
8
13 21 …
13 21 34 …
fibonacci sequence
tail of fibonacci sequence
2 3 5 8 13 21 34 55 …tail
of tail of fibonacci sequence
fibs :: [ Integer ]
fibs = 1 : 1 : (zipWith (+) fibs (tail fibs))
This is much faster! And uses less resources. Why?
Cse536 Functional Programming
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
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 tf3
tf 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
fibs = [1,1,2,3,5,8,…]
• Streams are “wires” along
which values flow.
(:)
[1,2,3,5,8, …]
1
(:)
1
• 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
[2,3,5,8,…]
add
•A stream diagram corresponds
to a Haskell function (usually
recursive)
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
+1 [0] next
0
inp
if*
out
Cse536 Functional Programming
Example
counter :: [ Bool ] -> [ Int ]
counter inp = out
where
out = if* inp then* 0 else* next
next = [0] followedBy map (+ 1) out
1...
0...
+1 [0] next
0
F...
if*
0...
out
Cse536 Functional Programming
Example
counter :: [ Bool ] -> [ Int ]
counter inp = out
where
out = if* inp then* 0 else* next
next = [0] followedBy map (+ 1) out
1:2..
0:1..
+1 [0] next
0
F:F..
if*
0:1..
out
Cse536 Functional Programming
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:1:2
+1 [0] next
0
F:F:T..
if*
0:1:0..
out
Cse536 Functional Programming
Client, Server Example
type Response = Integer
type Request = Integer
client :: [Response] -> [Request]
client ys = 1 : ys
server :: [Request] -> [Response]
server xs = map (+1) xs
Typical.
A set of mutually
reqs = client resps
recursive equations
resps = server reqs
Cse536 Functional Programming
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
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 = 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
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
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
Cse536 Functional Programming
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.
Cse536 Functional Programming
memo1
• We need a function that builds a table of
previous calls.
• Memo : (a -> b) -> (a -> b)
0
1
2
3
4
1 Memo fib x = if x in_Table_at i
1
then Table[i]
2
else set_table(x,fib x); return fib x
3
5
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 z is the error or non-terminating
computation. Think of z as an approximation to an
answer. We can get more precise approximations by:
ones = 1 : ones
z
z
1: 1:z
1:1:1:z
1:
Cse536 Functional Programming
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 }
Cse536 Functional Programming
Example
•
Prove: P{x} ==
(x ++ y) ++ w = x ++ (y++w)
1) Prove P{z}
(z ++ y) ++ w = z ++ (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
(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)
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 hypothesis
x : (xs ++ (y ++ w))
•
Def of (++)
(x:xs) ++ (y ++ w)
Related documents