1 / 40

CS5205: Foundation in Programming Languages

CS5205: Foundation in Programming Languages. Basics of Functional Programming. Topics. Higher-Order Functions Formal Reasoning Abstraction vs Efficiency Bridging the Divide. Function Abstraction.

frayne
Download Presentation

CS5205: Foundation in Programming Languages

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. CS5205: Foundation in Programming Languages Basics of Functional Programming. Haskell

  2. Topics • Higher-Order Functions • Formal Reasoning • Abstraction vs Efficiency • Bridging the Divide Haskell

  3. Function Abstraction • Function abstraction is the ability to convert any expression into a function that is evaluated at a later time. <Expr> p = \ () -> Expr time p () time Normal Execution Delayed Execution Haskell

  4. Higher-Order Functions • Higher-order programming treats functions as first-class, allowing them to be passed as parameters, returned as results or stored into data structures. • This concept supports generic coding, and allows programming to be carried out at a more abstract level. • Genericity can be applied to a function by letting specific operation/value in the function body to become parameters. Haskell

  5. foldr f u ls = case ls of [] -> u x:xs -> f x(foldr f u xs) Genericity • Replace specific entities (0 and +) by parameters. sumList ls = case ls of [] -> 0 x:xs -> x+(sumList xs) Haskell

  6. foldr :: (a -> b -> b) -> b -> [a] -> b Polymorphic, Higher-Order Types sumList :: [Int] -> Int sumList :: Num a => [a] -> a Haskell

  7. Instantiating Generic Functions sumL2 :: Num a => [a] -> a sumL2 ls = foldr (+)0 ls sumL2 [1, 2, 3] ) sumL2 [1.1, 3, 2.3] ) Haskell

  8. Instantiating Generic Functions prodL :: Num a => [a] -> a prodL ls = foldr (*)1 ls prodL [1, 2, 5] ) prodL [1.1, 3, 2.3] ) Haskell

  9. Instantiating Generic Functions • Can you express map in terms of foldr? map :: (a -> b) -> [a] -> [b] map f [] = [] map f (x:xs) = (f x) : (map f xs) map f xs = foldr … … … xs Haskell

  10. Can we express filter in terms of foldr? filter f xs = foldr … … … xs Instantiating Generic Functions • Filtering a list of elements with a predicate. filter :: (a -> Bool) -> [a] -> [a] filter f [] = [] filter f (x:xs) = if (f x) then x : (filter f xs) else filter f xs Haskell

  11. Similar to Unix pipe command: cmd1 | cmd2 Pipe/Compose compose :: (b -> c) -> (a -> b) -> a -> c compose f g = \ x -> f (g x) g | f = compose f g Haskell

  12. In Haskell, type class help give a more generic type: for :: Num b, Ord b => b -> b -> (b -> a -> a) -> a -> a Iterator Construct for :: Int -> Int -> (Int -> a -> a) -> a -> a for i j f a = if i>j then a else for (i+1) j (f i a) Haskell

  13. associate to right Right Folding foldr f u [x1,x2,..,xn] • f x1 (foldr f u [x2 ..xn]) • f x1 (f x2 (fold f u [x3..xn])) • f x1 (f x2 (… (fold f u [xn]) …)) • f x1 (f x2 (… (f xn u) …))) Haskell

  14. Left Folding – Tail Recursion • Accumulate result in a parameter: foldl f u ls = case ls of [] -> u x:xs -> foldl f (f u x) xs based on accumulation • What is the type of foldl? • Can we compute factorial using it? Haskell

  15. left is here! Left Folding foldl f u [x1,x2,..,xn] • foldl f (f u x1) [x2 ..xn] • foldl f (f (f u x1) x2) [x3..xn])) • foldl f (f … (f (f u x1) x2)… xn) [] • f (… (f (f u x1) x2) …) xn Haskell

  16. sumList ls = sumT 0 ls sumT acc ls = foldl (+) acc ls Instance of Left Folding • Summing a list by accumulation. sumT acc ls = case ls of [] -> 0 x:xs -> sumT (x+acc) xs Haskell

  17. Referential Transparency • An expression is referentially transparent if it can always be replaced by an equivalent expression with the same value and effect. Allows reasoning based on components. • Useful for: • simplifying algorithm • proving correctness • optimization + parallelization • Pure functions are referentially transparent, as relied on in mathematical reasoning. Haskell

  18. Equivalence Proof • Can we Prove : sumList xs = sumT 0 xs. • Generalise : (sumList xs)+a = sumT a xs. • By Induction • Case : x=[] • (sumList [])+a = sumT a [] • 0+a = a • Case : x=x:xs • (sumList x:xs)+a = sumT a (x:xs) • x+(sumList xs)+a = sumT (x+a) xs • (sumList xs)+(x+a) = sumT (x+a) xs • // apply induction hypothesis Haskell

  19. rev xs = foldr … … … What is the time complexity? List Reversal • Concatenate first element to last position. rev [] = [] rev (x:xs) = rev xs ++ [x] Haskell

  20. Time Complexity • Assume : C(xs++ys) = length xs • Derive :Steps(rev(xs)) • Case [] : • Steps(rev([])) = 1+Steps([]) • = 1+0 • Case x:xs : • Steps(rev(x:xs)) • = 1+Steps(rev(xs)++[a]) • = 1+C(rev(xs)++_)+Steps(rev(xs)) • = 1+length(rev(xs)+Steps(rev(xs)) • = 1+length(xs)+Steps(rev(xs)) • Thus : C(rev(xs)) = (length xs)^2 Haskell

  21. Same as: revT w xs = foldl (\ w x -> x:w) w xs What is the time complexity? Iterative List Reversal • Concatenate first element to last position. revT w [] = w revT w (x:xs) = revT (x:w) xs Haskell

  22. Time Complexity • DeriveSteps(revT w xs) • Case [] : • Steps(revT w []) = 1+Steps(w) • = 1+0 • Case x:xs : • Steps(revT w (x:xs)) • = 1+Steps(revT (x:w) xs) • = 1+Steps(revT _ xs) • Thus : C(revT w xs) = (length xs) Haskell

  23. Abstraction vs Efficiency • Abstraction  helps with programmers’ productivity • Efficiency  helps machine execution. • Tension between abstraction and efficiency • Abstract program • stress on ‘what’ rather than ‘how’ • typically uses simpler (maybe naïve) algorithm • Efficient program • optimised implementation • use of clever programming techniques Haskell

  24. Bridging the Divide Abstract Code/Specs transform or synthesize verify Efficient Code or Implementation Haskell

  25. Unfold/Fold Transformation • DEFINE - new function definition • UNFOLD – replace a call by its body • FOLD – replace an expression matching the RHS of a definition by its corresponding call • INSTANTIATE – provide special cases of a given equation. • ABSTRACT – introduce a tuple of expressions • LAW – application of valid lemma, e.g. associativity Haskell

  26. Fusion Transformation • Consider: • …sum (double xs)… • sum [] = 0 • sum x:xs = x+(sum xs) • double [] = [] • double x:xs = 2*x : (double xs) • Computation reuses smaller functions to build larger ones but may result in unnecessary intermediate structures. They can cause space overheads. • Solution : Fuse the code together! Haskell

  27. Fusion Transformation • Define: • sumdb xs = sum (double xs) • Instantiate: xs=[] • sumdb [] = sum (double []) • = sum [] • = 0 • Instantiate: xs=x:xs • sumdb x:xs = sum (double x:xs) • = sum (2*x : double xs) • = 2*x + sum(double xs) • = 2*x + (sumdb xs) Haskell

  28. Iteration Transformation • Define: • sumdbT a xs = a+(sumdb xs) • Instantiate: xs=[] • sumdbT a [] = a+(sumdb []) • = a • Instantiate: xs=x:xs • sumdbT a (x:xs) = a+(sumdb x:xs) • = a+(2*x + sumdb xs) • = (a+2*x) + (sumdb xs) • = sumdbT (a+2*x) xs Haskell

  29. Laziness vs Strictness • Laziness increase expressiveness, allowing infinite data structures, by not evaluating each subexpression until it is really needed. • However, there is a performance penalty (both space and time), as the suspended computation has to be stored as a closure and then invoked subsequently. • If you always need some of the parameters, we might as well evaluate their corresponding arguments first. • Question : When is an argument to a function needed (strict)? Using ? to denote non-termination. f … ? … = ? Haskell

  30. Strictness Transformation • Can analyse that accumulating argument of sumdb is strict. We can force strictness using the `seq` operator. • sumdbT a [] = a • sumdbT a (x:xs) = sumdbT (a+2*x) xs • sumdbT a [] = a • sumdbT a (x:xs) = let p = a+2*x in • p `seq` sumdbT p xs Haskell

  31. Tupling Transformation • Average of a List : • average xs = sum xs / length xs • Define : • both xs = (sum xs, length xs) • Instantiate : • both [] = (sum [], length []) • = (0,0) • Instantiate : • both x:xs = (sum x:xs, length x:xs) • = (x+sum xs, 1+length xs) • = let (u,v)= (sum xs,length xs) in • (x+u, 1+v) • = let (u,v)= both xs in u/v Haskell

  32. Naive Fibonacci • Natural but inefficient version of fibonacci : • fib 0 = 1 • fib 1 = 1 • fib n = (fib n-1)+(fib n-2) • Time complexity is exponential time due to presence of redundant calls. Haskell

  33. A Call Tree of fib fib 6 fib 4 fib 5 fib 4 fib 3 fib 3 fib 2 fib 3 fib 2 fib 2 fib 1 fib 2 fib 1 Many repeated calls! Haskell

  34. A Call Graph of fib fib 6 fib 5 fib 4 fib 3 fib 2 fib 1 No repeated call through reuse of identical calls Haskell

  35. Tupling - Computing Two Results Compute two calls from next two calls in hierarchy: ((fib n) , (fib n-1)) ((fib n-1) , (fib n-2)) Haskell

  36. Tupling Fibonacci • Define : • fibtup n = (fib n+1, fib n) • Instantiate : • fibtup 0 = (fib 1, fib 0) • = (1,1) • Instantiate : • fibtup n+1 = (fib n+2, fib n+1) • = ((fib n+1)+(fib n), fib n+1) • = let (u,v)= (fib n+1, fib n) • in (u+v, u) • = let (u,v)= fibtup n in (u+v, u) Haskell

  37. Using the Tupled Function • fib 0 = 1 • fib 1 = 1 • fib n = fib n-1 + fib n-2 • = let (u,v) = (fib n-1,fib n-2) • in u+v • = let (u,v) = fibtup (n-2) • in u+v Haskell

  38. Linear Recursion fib 6 fib 5 • fibtup 0 = (1,1) • fibtup (n+1) = • let (u,v)= fibtup n • in (u+v,u) fib 4 fib 3 fib 2 fib 1 Haskell

  39. To Iteration fib 6 fib 5 • fibT 0 u v • = (u,v) • fibT (n+1) u v • = fibT n (u+v,u) fib 4 fib 3 fib 2 fib 1 Haskell

  40. Optimization • Should be done only if critical. • Should be automated where possible, for e,g. as part of compilation. • Manual optimization by human should preferably be carefully checked or verified Haskell

More Related