### code from today

parent 3f6e24e2
 (* CSE 341 *) (* First-Class Functions *) let double x = x * 2 let incr x = x + 1 let funcs = [double; incr] let rec apply_funcs (fs,x) = match fs with | [] -> x | f :: fs' -> apply_funcs (fs', f x) (* binds foo to 201 *) let foo = apply_funcs (funcs, 100) (* binds bar to 202 *) let bar = apply_funcs (List.rev funcs, 100) (* it should really bother us to write these functions separately *) let rec increment_n_times_bothersome (n, x) = if n = 0 then x else 1 + increment_n_times_bothersome (n - 1, x) let rec double_n_times_bothersome (n, x) = if n = 0 then x else 2 * double_n_times_bothersome (n - 1, x) let rec tail_n_times_bothersome (n, xs) = if n = 0 then xs else List.tl (tail_n_times_bothersome (n - 1, xs)) (* much better: abstract the common pieces into a function *) let rec n_times (f, n, x) = if n = 0 then x else f (n_times (f, n - 1, x)) (* we can now implement the 3 bothersome functions above in one line each *) let increment_n_times (n, x) = n_times (incr, n, x) let double_n_times (n, x) = n_times (double, n, x) let tail_n_times (n, xs) = n_times (List.tl, n, xs) (* and nothing stops us from using n_times in places we didn't originally plan *) let triple x = 3 * x let triple_n_times (n, x) = n_times (triple, n, x) (* polymorphic but not higher order *) let rec len xs = match xs with | [] -> 0 | _ :: xs' -> 1 + len xs' (* higher order but not polymorphic *) let rec times_until_zero (f, x) = if x = 0 then 0 else 1 + times_until_zero (f, f x) (* two very useful and very common higher-order functions *) let rec map (f, xs) = match xs with | [] -> [] | x :: xs' -> (f x) :: (map (f, xs')) let rec filter (f, xs) = match xs with | [] -> [] | x :: xs' -> if f x then x :: filter (f,xs') else filter (f,xs') (* motivating anonymous functions *) (* if we just need is_even for only_evens, better to use local function *) let only_evens2 xs = let is_even x = x mod 2 = 0 in filter (is_even, xs) (* actually, we could define it *right* where we need it *) let only_evens3 xs = filter ((let is_even x = x mod 2 = 0 in is_even), xs) (* seems kind of silly to have a let expression whose body is the variable... can we do better? *) (* not like this. a let binding is not an expression! *) (* let only_evens4 xs = filter ((let is_even x = x mod 2 = 0), xs) *) (* but an anonymous function is an expression! *) let only_evens5 xs = filter ((fun x -> x mod 2 = 0), xs) (* bad style: the 'if e then true else false' of functions *) (* "unnecessary function wrapping" *) let tail_n_times_bad_style (n, xs) = n_times ((fun ys -> List.tl ys), n, xs) (* good style *) let tail_n_times_good_style (n, xs) = n_times (List.tl, n, xs) (* ---------------------------------------- *) (* you can return functions from functions as well *) let mult_by_n n = fun x -> n * x (* notice how this is different from a simple multiplication function *) let multiply (n, x) = n * x (* look at the types! *) (* another example *) let double_or_triple f = if f 7 then fun x -> 2 * x else fun x -> 3 * x let roundabout_double = double_or_triple (fun x -> x - 3 = 4) let roundabout_nine = (double_or_triple (fun x -> x = 42)) 3 (* ---------------------------------------- *) (* higher-order functions over our own recursive variant types *) type exp = | Const of int | Negate of exp | Add of exp * exp | Multiply of exp * exp let rec true_of_all_constants (f, e) = match e with | Const n -> f n | Negate e' -> true_of_all_constants (f, e') | Add (e1, e2) -> true_of_all_constants (f, e1) && true_of_all_constants (f, e2) | Multiply (e1, e2) -> true_of_all_constants (f, e1) && true_of_all_constants (f, e2) let all_even_constants e = true_of_all_constants ((fun x -> x mod 2 = 0), e)
 (* first class functions aka "functions are values" Functional programming - expression-oriented (things nest!) - variant types and pattern matching - first-class functions "first-class" means "as good as anything else" or "treated as well as anything else" - can put into data structure - can pass as arguments to functions - can return as result of function lots of first class things in OCaml (all values!) - integers - boolean - lists - pairs and tuples - records - variants *) let x = 1 let y = 2 let l = [x; y] let rec f (n, q) = match q with | [] -> n | x :: xs -> x + f (n, xs) let m = f (17, l) (* so far, functions are not like this!! all you can do is define it either at top level or locally in a let expression and you can call it what would mean to "put a function into a list" or "pass a function as an argument to another function" *) (* but in fact in OCaml, functions are first class, we just never told you that. *) let double x = 2 * x let incr x = x + 1 let funcs: (int -> int) list = [double; incr] (* new way to write down types: "arrow types" which are the type of functions if f has type t1 -> t2 then f takes a t1 as an arg and returns a t2 *) (* a variable binding that binds a function value to a name! *) let y = List.hd funcs let z = List.hd (List.tl funcs) (* applies all the functions in funcs to x in left-to-right order *) let rec apply_funcs (funcs, x) = match funcs with | [] -> x | f :: fs -> apply_funcs (fs, f(x)) (* repl prints: *) (* val apply_funcs : ('a -> 'a) list * 'a -> 'a = *) let ans = apply_funcs (funcs, 3) (* double(3) = 6 incr(6) = 7 so the answer is 7 *) let ans_backwards = apply_funcs (List.rev funcs, 3) (* incr(3) = 4 double(4) = 8 so the answer is 8 *) (* passing functions as arguments to other functions *) let rec incr_by_n (n, x) = if n = 0 then x else 1 + incr_by_n (n-1, x) let rec double_n_times (n, x) = if n = 0 then x else 2 * double_n_times (n-1, x) let rec tail_n_times (n, l) = if n = 0 then l else List.tl (tail_n_times (n-1, l)) (* the argument f is a function!! *) let rec n_times (f, n, x) = if n = 0 then x else f (n_times (f, n-1, x)) let incr_by_n_better (n, x) = n_times (incr, n, x) let double_n_times_better (n, x) = n_times (double, n, x) let tail_n_times_better (n, l) = n_times (List.tl, n, l) let triple x = 3 * x let triple_n_times (n, x) = n_times (triple, n, x) (* this idea is called "higher-order" function. "function that takes a function". *) (* "roll your own language features / control flow" *) (* three different phrases - first-class functions - not a function! it's the name of a design aspect of the language that treats functions as "normal" values - higher-order functions - a function that takes a function as an argument - (or returns a function as a result) - polymorphic functions - a function with one of those 'a thingies in its type *) let decr x = x - 1 (* higher-order function that is not polymorphic *) let rec times_until_zero ((f: int -> int), (x: int)): int = if x = 0 then 0 else 1 + times_until_zero (f, f(x)) (* james made a mistake here during class. these notes are correct. the video is wrong. *) (* polymorphic but not higher-order *) let rec len l = match l with | [] -> 0 | _ :: xs -> 1 + len xs (* hall of fame of higher-order functions *) (* return a list of results from f applied to all the elements of xs *) let rec map (f, xs) = match xs with | [] -> [] | x :: xs -> f(x) :: map (f, xs) let _ = map (incr, [1; 2; 3]) (* [2; 3; 4]*) let _ = map (double, [1; 2; 3]) (* [2; 4; 6]*) (* val map : ('a -> 'b) * 'a list -> 'b list = *) (* map is a function that takes two arguments - first argument is a function 'a -> 'b -- literally any function - second argument is a list of 'a map returns a list of 'b *) (* return a new list containing only those elements of xs for which f(x) is true (in same order as input list) *) let rec filter (f, xs) = match xs with | [] -> [] | x :: xs -> if f(x) then x :: filter (f, xs) else filter (f, xs) let is_even x = x mod 2 = 0 let is_odd x = x mod 2 = 1 let _ = filter (is_even, [1; 2; 3]) (*  *) let _ = filter (is_odd, [1; 2; 3]) (* [1; 3] *) (* val filter : ('a -> bool) * 'a list -> 'a list = *) (* filter is a function that takes two arguments - the first is a function 'a -> bool -- takes anything and returns a bool - the second arg is a list of 'a return value is also a list of 'a *) let _ = let is_even x = x mod 2 = 0 in filter (is_even, [1; 2; 3]) let _ = filter (let is_even x = x mod 2 = 0 in is_even, [1; 2; 3]) (* anonymous functions *) let _ = filter ((fun x -> x mod 2 = 0), [1; 2; 3])
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment