Recap from last Week Three key ways to build complex types/values 1. Each-of types Value of T contas value of T1 and a value of T2 2. One-of types Value of T contas value of T1 or a value of T2 Today More on recursion Higher-order functions takg and returng functions 3. Recursive Value of T contas (sub)-value of same type T 1 2 Factorial Factorial let rec fact n = let rec fact n = if n<=0 then 1 else n * fact (n-1);; 3 4 How does it execute? let rec fact n = if n<=0 then 1 else n * fact (n-1);; fac 3;; How does it execute? let rec fact n = if n<=0 then 1 else n * fact (n-1);; fac 3;; 5 6 1
Tail recursion Tail recursion: recursion where all recursive calls are followed by a return other words: not allowed to do any between recursive call and return Tail recursive factorial 7 8 Tail recursive factorial How does it execute? let rec helper x curr = if x <= 0 then curr else helper (x - 1) (x * curr) helper x 1;; let rec helper x curr = if x <= 0 then curr else helper (x - 1) (x * curr) helper x 1;; fact 3;; 9 10 How does it execute? let rec helper x curr = if x <= 0 then curr else helper (x - 1) (x * curr) helper x 1;; fact 3;; Tail recursion Tail recursion: recursion where all recursive calls are followed by a return other words: not allowed to do any between recursive call and return Why do we care about tail recursion? it turns out that tail recursion can be optimized to a simple loop 11 12 2
Compiler can optimize! Tail recursion summary let rec helper x curr = if x <= 0 fact(x) { curr := 1; while (1) { if (x <= 0) Tail recursive calls can be optimized as a jump then curr else helper (x - 1) (x * curr) helper x 1;; } then { return curr } else { x := x 1; curr := (x * curr) } Part of the language specification of some languages (ie: you can count on the compiler to optimize tail recursive calls) recursion! Loop! 13 14 More recursion: terval terval (* return a list that contas the tegers i through j clusive *) let rec terval i j = (* return a list that contas the tegers i through j clusive *) let rec terval i j = if i > j then [] else i::(terval (i+1) j);; 15 16 terval function with it fn terval function with it fn (* return a list that contas the elements f(i), f(i+1),... f(j) *) let rec terval_it i j f = (* return a list that contas the elements f(i), f(i+1),... f(j) *) let rec terval_it i j f = if i > j then [] else (f i)::(terval_it (i+1) j f);; 17 18 3
terval function aga terval function aga (* our regular terval function terms of the one with the it function *) let rec terval i j = (* our regular terval function terms of the one with the it function *) let rec terval i j = terval_it i j (fun x -> x);; 19 20 Interval function yet aga! Function Curryg (* let's change the order of parameters... *) let rec terval_it f i j = if i > j then [] else (f i)::(terval_it f (i+1) j);; (* now can use curryg to get terval function! *) let terval = terval_it (fun x -> x);; 21 In general, these two are equivalent: let f = fun x1 -> -> fun xn -> e let f x1 xn = e Multiple argument functions by returng a function that takes the next argument Named after a person (Haskell Curry) 22 Function Curryg vs tuples Function Curryg vs tuples Tuple version: fn defition let f (x1,,xn) = e fn call f (x1,,xn) Consider the followg: let lt x y = x < y; Curried version: fn defition let f x1 xn = e fn call f x1 xn 23 Could have done: let lt (x,y) = x<y; But then no testers possible In general: Curryg allows you to set just the first n params (where n smaller than the total number of params) 24 4
filter filter (* return a list contag all elements of l for which f returns true *) let rec filter f l = 25 (* return a list contag all elements of l for which f returns true *) let rec filter f l = [] -> [] h::t -> let t' = (filter f t) if (f h) then h::t' else t';; 26 map map (* return the list contag f(e) for each element e of l *) let rec map f l = (* return the list contag f(e) for each element e of l *) let rec map f l = [] -> [] h::t -> (f h)::(map f t);; 27 28 composg functions (f o g) (x) = f(g(x)) (* return a function that given an argument x applies f2 to x and then applies f1 to the result*) let compose f1 f2 = composg functions (f o g) (x) = f(g(x)) (* return a function that given an argument x applies f2 to x and then applies f1 to the result*) let compose f1 f2 = fun x -> (f1 (f2 x));; (* another way of writg it *) let compose f1 f2 x = f1 (f2 x);; 29 30 5
Higher-order functions! Higher-order functions! let map_cr_2 = compose map_cr map_cr;; map_cr_2 (terval (-10) 10);; let map_cr_3 = compose map_cr map_cr_2;; map_cr_3 (terval (-10) 10);; let map_cr_3_pos = compose pos_filer map_cr_3;; map_cr_3_pos (terval (-10) 10);; (compose map_cr_3 pos_filer) (terval (-10) 10);; let map_cr_2 = compose map_cr map_cr;; map_cr_2 (terval (-10) 10);; let map_cr_3 = compose map_cr map_cr_2;; map_cr_3 (terval (-10) 10);; let map_cr_3_pos = compose pos_filer map_cr_3;; map_cr_3_pos (terval (-10) 10);; (compose map_cr_3 pos_filer) (terval (-10) 10);; 31 Instead of manipulatg lists, we are manipulatg the list manipulators! 32 max function max function let max x y = if x < y then y else x;; let max x y = if x < y then y else x;; (* return max element of list l *) let list_max l = 33 (* return max element of list l *) let list_max l = h::t -> helper (max h curr) t helper 0 l;; 34 concat function concat function (* concatenate all strgs a list *) let concat l = (* concatenate all strgs a list *) let concat l = h::t -> helper (curr ^ h) t helper "" l;; 35 36 6
What s the pattern? fold let list_max l = h::t -> helper (max h curr) t helper 0 l;; (* to help us see the pattern: *) let list_max l = h::t -> helper (max h curr) t helper 0 l;; let concat l = h::t -> helper (curr ^ h) t helper "" l;; 37 (* fold, the coolest function there is! *) let rec fold f curr l = 38 fold fold (* fold, the coolest function there is! *) let rec fold f curr l = h::t -> fold f (f h curr) t;; (* fold, the coolest function there is! *) let rec fold f curr l = h::t -> fold f (f h curr) t;; 39 40 Examples of fold Examples of fold let list_max = let list_max = fold max 0;; let concat = let concat = fold (^) "";; let multiplier = let multiplier = fold (*) 1;; 41 42 7
Examples of fold let fact n = multiplier (terval 1 n);; Examples of fold let cons x y = x::y;; let f = fold cons [];; (* same as: let f l = fold cons [] l *) Notice how all the recursion is buried side two functions: terval and fold! 43 44 Examples of fold let cons x y = x::y;; let f = fold cons [];; (* same as: let f l = fold cons [] l *) Benefits of higher-order functions Identify common computation patterns Iterate a function over a set, list, tree Accumulate some value over a collection Pull out (factor) common code: Computation Patterns Re-use many different situations 45 46 Funcs takg/returng funcs Higher-order funcs enable modular code Each part only needs local formation Data Structure Client Uses list Uses meta-functions: map,fold,filter Data Structure Library list Provides meta-functions: map,fold,filter Different way of thkg Free your md -Morpheus Different way of thkg about computation Manipulate the manipulators With locally-dependent funs to traverse, accumulate over (lt h), square etc. lists, trees etc. Without requirg Implement. Meta-functions don t need client details of data structure fo 47 48 8