### import unit3 code

parent 503d39ea
 (* CSE 341, Lecture 8 *) (*#utop_prompt_dummy let _ = UTop.set_show_box false *) (* Lecture 8: 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)
 (* CSE 341, Lecture 9 *) (*#utop_prompt_dummy let _ = UTop.set_show_box false *) (* lexical scope examples to learn the rules *) (* 1 *) let x = 1 (* 2 *) let f y = x + y (* 3 *) let x = 2 (* 4 *) let y = 3 (* 5 *) let z = f (x + y) (* 1 *) let x = 1 (* 2 *) let f y = (* 2 a *) let x = y + 1 in (* 2 b *) fun q -> x + y + q (* 3 *) let x = 3 (* 4 *) let g = f 4 (* 5 *) let y = 5 (* 6 *) let z = g 6 (* 1 *) let f g = (* 1 a *) let x = 3 in (* 1 b *) g 2 (* 2 *) let x = 4 (* 3 *) let h y = x + y (* 4 *) let z = f h (* let y = 5 *) (* lexical scope examples to motivate the rules *) (* f1 and f2 are always the same, no matter where used *) let f1 y = let x = y + 1 in fun z -> x + y + z let f2 y = let q = y + 1 in fun z -> q + y + z let h1 = f1 7 let h2 = f2 7 let x = 17 (* irrelevant *) let a1 = h1 4 let a2 = h2 4 (* f3 and f4 are always the same, no matter what argument is passed in *) let f3 g = let x = 3 in (* irrelevant *) g 2 let f4 g = g 2 let x = 17 let a3 = f3 (fun y -> x + y) let a4 = f4 (fun y -> x + y) let a5 = f3 (fun y -> 17 + y) let a6 = f4 (fun y -> 17 + y) (* under dynamic scope, the call to g below would: - try to add a string x to an int - have an unbound variable y even though g type checked! *) let x = "hi" let g = f1 7 let z = g 4 (* lexical scope examples to leverage the rules *) (* lexical scope very useful with higher-order functions *) (* our first example of "currying"; will study and use more soon *) let rec filter f = (fun xs -> match xs with | [] -> [] | x :: xs' -> if f x then x :: ((filter f) xs') else ((filter f) xs')) let greater_than x = fun y -> x < y let is_positive = greater_than 0 let only_positives = filter is_positive let all_greater (xs, n) = (filter (greater_than n)) xs (* let's start using that e1 e2 e3 is (e1 e2) e3 *) let all_shorter (xs, s) = filter (fun x -> String.length x < String.length s) xs let all_shorter' (xs, s) = (* why is this potentially faster? *) let n = String.length s in filter (fun x -> String.length x < n) xs let rec fold_left (f, acc, xs) = match xs with | [] -> acc | x :: xs' -> fold_left (f, (f (acc, x)), xs') (* examples that do not capture private data *) let sum xs = fold_left ((fun (acc, x) -> acc + x), 0, xs) let only_positives xs = fold_left ((fun (acc, x) -> acc && x >= 0), true, xs) (* examples that *do* capture private data *) let count_in_range (lo, hi, xs) = fold_left ((fun (acc, x) -> acc + (if lo <= x && x < hi then 1 else 0)), 0, xs) let are_all_shorter (xs, s) = let n = String.length s in fold_left ((fun (acc, x) -> acc && String.length x < n), true, xs) let forall (f, xs) = fold_left ((fun (acc, x) -> acc && f x), true, xs) let only_positives' xs = forall ((fun x -> x > 0), xs) let are_all_shorter' (xs, s) = let n = String.length s in forall ((fun x -> String.length x < n), xs)
 (* CSE 341, Lecture 10 *) (*#utop_prompt_dummy let _ = UTop.set_show_box false *) (* function composition (right-to-left, like math) *) let compose = fun f -> fun g -> fun x -> f (g x) (* infix notation for composition *) let (%) = compose let double_plus_one x = compose (fun x -> x + 1) (fun x -> 2 * x) x let _ = double_plus_one 3 (* "variable-style" let binding is better style *) let double_plus_one = compose (fun x -> x + 1) (fun x -> 2 * x) let _ = double_plus_one 3 (* also nice to use the infix operator *) let double_plus_one = (fun x -> x + 1) % (fun x -> 2 * x) let _ = double_plus_one 3 let sqrt_of_abs i = Float.sqrt (float_of_int (Int.abs i)) let sqrt_of_abs i = (Float.sqrt % float_of_int % Int.abs) i let sqrt_of_abs = Float.sqrt % float_of_int % Int.abs let _ = sqrt_of_abs (-8) (* pipeline operator (left-to-right) *) (* actually built-in to OCaml, but here's the definition *) let (|>) x f = f x let sqrt_of_abs i = i |> Int.abs |> float_of_int |> Float.sqrt let _ = sqrt_of_abs (-8) (* also left-to-right *) let pipeline_option (f, g) = fun x -> match f x with | None -> None | Some y -> g y let sqrt_if_positive = pipeline_option ((fun i -> if i > 0 then Some (float_of_int i) else None), (fun x -> Some x) % sqrt) let _ = sqrt_if_positive 3 let _ = sqrt_if_positive (-3) (* ---------------------------------------- *) (* Currying *) let sorted3_tuple (x, y, z) = x <= y && y <= z let _ = sorted3_tuple (7, 9, 11) let sorted3 = fun x -> fun y -> fun z -> x <= y && y <= z let _ = ((sorted3 7) 9) 11 let _ = sorted3 7 9 11 let sorted3_spaces_fun = fun x y z -> x <= y && y <= z let _ = sorted3_spaces_fun 7 9 11 let sorted3_spaces x y z = x <= y && y <= z let _ = sorted3_spaces 7 9 11 (* fold again, but now curried *) (* this exact definition is in the stdlib at List.fold_left *) let rec fold_left f acc xs = match xs with | [] -> acc | x :: xs' -> fold_left f (f acc x) xs' let sum_meh_style xs = fold_left (fun acc x -> acc + x) 0 xs let sum_good_style = fold_left (fun acc x -> acc + x) 0 let remove_negs_meh xs = List.filter (fun x -> x >= 0) xs (* partial application and currying allows us to use "variable-style" let *) let remove_negs = List.filter (fun x -> x >= 0) let remove_all n = List.filter (fun x -> x <> n) let remove_zeros = remove_all 0 let increment_all = List.map (fun x -> x + 1) (* in the library as List.exists *) let rec exists p xs = match xs with | [] -> false | x :: xs' -> p x || exists p xs' let exists p xs = List.fold_left (fun acc x -> acc || p x) false xs let exists p = List.fold_left (fun acc x -> acc || p x) false (* in the library as List.for_all *) let forall p = List.fold_left (fun acc x -> acc && p x) true let has_zero = exists (fun x -> x = 0) let no_zeros = forall (fun x -> x <> 0) (* currying is the norm in OCaml, even if partial application unlikely *) let rec append xs ys = match xs with | [] -> ys | x::xs' -> x :: append xs' ys (* revisit compose *) let compose_shorter f g x = f (g x) (* converting between curried and tupled versions of a function *) let curried_of_paired f x y = f (x, y) let paired_of_curried f (x, y) = f x y (* more verbose but less "tricky" versions of the above: *) (* let curried_of_paired f = fun x -> fun y -> f (x, y) let paired_of_curried f = fun (x, y) -> (f x) y *) (* check out how much the types tell us above and here: *) let swap_tupled f (x, y) = f (y, x) let swap_curried f x y = f y x let rec range (lo, hi) = if lo > hi then [] else lo :: range (lo + 1, hi) (* no problem using range as curried even though it's tupled -- convert it *) let countup = curried_of_paired range 0 let _ = countup 5 (******** value restriction *********) (* let remove_empty_lists = List.filter (fun x -> List.length x > 0) (* look at the type *) let _ = remove_empty_lists [[]; ] (* *now* look at the type!! *) let _ = remove_empty_lists [[]; [true]] (* oh no! *) *) (* workaround 1: go back to bad style :\ *) let remove_empty_lists ls = List.filter (fun x -> List.length x > 0) ls let _ = remove_empty_lists [[]; ] let _ = remove_empty_lists [[]; [true]] (* ---------------------------------------- *) (* refs and mutable state *) let x = ref 42 let y = ref 42 let z = x let _ = x := 43 let w = !x + !z (* does not typecheck: *) (* let _ = x + 1 *) (* ---------------------------------------- *) (* callback library *) let callbacks : (int -> unit) list ref = ref [] let on_key_event f = callbacks := f :: !callbacks (* like map, but produces no data *) (* in the library as List.iter *) let rec iter f xs = match xs with | [] -> () | x :: xs' -> f x; iter f xs' let do_key_event i = List.iter (fun f -> f i) !callbacks (* callback client *) let times_pressed = ref 0 (* actually built-in, but here's the definition *) let incr int_ref = int_ref := !int_ref + 1 let () = on_key_event (fun _ -> incr times_pressed) let () = do_key_event 97 let () = do_key_event 98 let () = do_key_event 99 let _ = !times_pressed let print_if_pressed i = on_key_event (fun j -> if i = j then print_endline ("pressed " ^ string_of_int i) else ()) let () = do_key_event 97 let () = print_if_pressed 122 let () = do_key_event 98 let () = do_key_event 122 let _ = !times_pressed (* ---------------------------------------- *) (* ADTs via closures *) type set = S of { insert : int -> set; member : int -> bool; size : unit -> int; } let empty_set = let rec make_set xs = (* xs is "private field" in result *) let contains i = List.mem i xs in (* contains is "private method" *) S { insert = (fun i -> if contains i then make_set xs else make_set (i :: xs)); member = contains; size = (fun () -> List.length xs) } in make_set [] (* client *) let _ = let S s1 = empty_set in let S s2 = s1.insert 34 in let S s3 = s2.insert 34 in let S s4 = s3.insert 19 in s4.size ()
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