Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
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)