Commit 0de2eedf authored by James R. Wilcox's avatar James R. Wilcox
Browse files

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 = <fun> *)
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 = <fun> *)
(* 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]) (* [2] *)
let _ = filter (is_odd, [1; 2; 3]) (* [1; 3] *)
(* val filter : ('a -> bool) * 'a list -> 'a list = <fun> *)
(* 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