Commit 43f079a5 authored by James R. Wilcox's avatar James R. Wilcox
Browse files

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 [[]; [1]]
(* 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 [[]; [1]]
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 = <fun> *)
(* remember this is equivalent to parentheses: *)
(* val convert_from_tupled_to_curried : ('a * 'b -> 'c) -> ('a -> 'b -> 'c) = <fun> *)
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