Commit e7ffe55c authored by Dan Grossman's avatar Dan Grossman
Browse files

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 [[]; [1]]
(* *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 [[]; [1]]
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