Download S14Streams

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

* Your assessment is very important for improving the workof 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