### code from friday

parent 30b634fb
 (* Curried filter *) 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 contains_only_positives = filter is_positive let all_greater (xs, n) = (filter (greater_than n)) xs let rec sum xs = match xs with | [] -> 0 | x :: xs -> x + sum xs let all_whose_sum_is_greater_than_sum (xss, ys) = (filter (fun xs -> sum xs > sum ys)) xss (* why is this potentially faster? *) let all_whose_sum_is_greater_than_sum' (xss, ys) = let n = sum ys in (filter (fun xs -> sum xs > n)) xss (* another hall of fame function *) 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 contains_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_sums_greater_than (xss, ys) = let n = sum ys in fold_left ((fun (acc, xs) -> acc && sum xs > n), true, xss) let for_all (f, xs) = fold_left ((fun (acc, x) -> acc && f x), true, xs) let contains_only_positives' xs = for_all ((fun x -> x > 0), xs) let are_all_sums_greater_than' (xss, ys) = let n = sum ys in for_all ((fun xs -> sum xs > n), xss) (* 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 let is_positive = sorted3_spaces 0 0 (* 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 for_all p = List.fold_left (fun acc x -> acc && p x) true let has_zero = exists (fun x -> x = 0) let no_zeros = for_all (fun x -> x <> 0) (* currying is the norm in OCaml, even if partial application is unlikely *) let rec append xs ys = match xs with | [] -> ys | x::xs' -> x :: append xs' ys (******** value restriction *********) let remove_empty_lists xs = List.filter (fun x -> List.length x > 0) xs (* look at the type, it's not 'a list list -> 'a list list as we would expect *) let _ = remove_empty_lists [[]; [true]] (* *now* look at the type!! *) let _ = remove_empty_lists [[]; ] (* oh no - that didn't work! *) (* workaround if you want polymorphics: go back to "bad" style :\ *) let remove_empty_lists xs = List.filter (fun x -> List.length x > 0) xs let _ = remove_empty_lists [[]; ] let _ = remove_empty_lists [[]; [true]] (* next idiom: combining functions *) (* function composition (right-to-left, like math) *) let compose = fun f -> fun g -> (fun x -> f (g x)) let compose_shorter f g x = f (g x) (* infix notation for composition *) let (%) = compose (* unnecessary function wrapping again here: *) 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) (* 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 (* ---------------------------------------- *) (* 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 = (* only library binding that clients should use *) callbacks := f :: !callbacks let rec iter f xs = (* like map, but produces no data. (In the library as List.iter.) *) match xs with | [] -> () | x :: xs' -> let _ = f x in iter f xs' let do_key_event i = List.iter (fun f -> f i) !callbacks (* end of callback library implementation *) (* 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 _ = !times_pressed (* callback has not been called yet *) (* imagine these happened from "the outside world" *) let () = do_key_event 97 let () = do_key_event 98 let () = do_key_event 99 (* we can see our callback was called *) 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 a "private field" in result *) let contains i = List.mem i xs in (* contains is a "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 ()
 let x = 1 (* why is lexical scope useful? *) (* 3 reasons why lexical scope is better - "alpha renaming" or "alpha equivalence": "variable names don't mattern" - write the same program twice using different variable names, as long I'm consistent within each version, the programs should be equivalent - lexical scope supports type checking (or scope checking) - can do local type checking - allows closures to safely capture data they need to do their work *) let f x = (* we say this anonymous function "captures" x *) fun y -> x + y let f2 z = fun y -> z + y (* under dynamic scope, could get different answers*) let g = f 3 (* spec: g adds 3 to its argument *) let x = 1 let a = g 4 (* lexical scope: 7 *) (* dynamic scope: 5 *) (* "how to program with closures" *) (* currying *) let rec filter (f, xs) = match xs with | [] -> [] | x :: xs -> if f x then x :: filter (f, xs) else filter (f, xs) let only_positive xs = filter ((fun x -> x > 0), xs) (* List.filter *) let rec filter f = fun xs -> match xs with | [] -> [] | x :: xs -> if f x then x :: (filter f) xs else (filter f) xs let only_positive xs = (filter (fun x -> x > 0)) xs let only_positive xs = filter (fun x -> x > 0) xs (* partial application -- passing only some of the arguments, get back a function expecting rest *) let only_positive = (filter (fun x -> x > 0)) let only_positive = filter (fun x -> x > 0) let rec filter f xs = match xs with | [] -> [] | x :: xs -> if f x then x :: filter f xs else filter f xs let rec filter = fun f -> fun xs -> match xs with | [] -> [] | x :: xs -> if f x then x :: filter f xs else filter f xs (* two abbreviations that support currying for all function definitions and calls: - definitions let f x y = ... is shorthand for let f = fun x -> fun y -> ... - calls f e1 e2 is shorthand for (f e1) e2 *) let rec sum xs = match xs with | [] -> 0 | x :: xs -> x + sum xs let all_whose_sum_is_greather_than_sum (xss, ys) = filter (fun xs -> sum xs > sum ys) xss let l = [[1; 2; 3]; [4; 5; 6]] let l2 = all_whose_sum_is_greather_than_sum (l, [4; 5]) let all_whose_sum_is_greather_than_sum' (xss, ys) = let n = sum ys in filter (fun xs -> sum xs > n) xss let all_whose_sum_is_greather_than_sum' (xss, ys) = filter (fun xs -> let n = sum ys in sum xs > n) xss (* another hall of fame function *) let rec fold_left f acc xs = match xs with | [] -> acc | x :: xs' -> fold_left f (f acc x) xs' let sum_via_fold xs = fold_left (fun acc x -> acc + x) 0 xs let sum_via_fold = fold_left (fun acc x -> acc + x) 0 let count_in_range lo hi = (* in the anonymous function below, "lo" and "hi" come from the outer environment *) fold_left (fun acc x -> if lo <= x && x < hi then 1 + acc else acc) 0 (* "use a variable-style let binding, not a function-style let binding "*) let rec append xs ys = match xs with | [] -> ys | x :: xs' -> x :: append xs' ys let f = append [1; 2; 3] (* f takes a list of integers and appends [1; 2; 3] to the beginning *) (* the VALUE RESTRICTION *) let remove_empty_lists xss = List.filter (fun xs -> List.length xs > 0) xss let remove_empty_lists = fun xss -> List.filter (fun xs -> List.length xs > 0) xss let remove_empty_lists2 = List.filter (fun xs -> List.length xs > 0) (* fix by re-introducing "unnecessary" (actually necessary) function wrapping *) let remove_empty_lists2 xss = List.filter (fun xs -> List.length xs > 0) xss (* converting back and forth between tupled and curried multi-arg functions *) let convert_from_tupled_to_curried f = fun x -> fun y -> f (x, y) (* val convert_from_tupled_to_curried : ('a * 'b -> 'c) -> 'a -> 'b -> 'c = *) (* remember this is equivalent to parentheses: *) (* val convert_from_tupled_to_curried : ('a * 'b -> 'c) -> ('a -> 'b -> 'c) = *) let curry f = fun x -> fun y -> f (x, y)
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