CMSC330
Higher Order Functions
Higher Order Functions
Higher Order Programming
Higher Order Functions
Map and Fold
Higher Order Programming
Recall Lambdas in Python
We can pass procs in as arguments
| p = lambda x: x + 1 |
| def f(x) |
| puts x(3) |
Treating code and functions as data
We can do this and more in OCaml
Higher Order Functions
Anonymous Functions
Anonymous function: function not bound to a variable
Syntax: fun x1 ... xn -> e
Technically functions are anonymous functions with syntactic sugar
| let add3 = fun x -> x + 3 |
Higher Order Functions
Recall Referential Transparency
Functions are expressions
| (* function_call.ml *) |
| let add3 x = x + 3 |
| let add3 = fun x -> x + 3 |
| add3 4 |
| (fun x -> x + 3) 4 |
So treat them like expressions
| let plus3 = add3;; |
| plus3 4;; |
Higher Order Functions
Can pass in functions as arguments
| |
| let apply f x = f x;; |
| |
| let sub3 x = x - 3;; |
| apply_to_int add3 4;; |
| apply_to_int sub3 4;; |
Recall Functions have types
| |
| let apply_to_int f x = f (x+1);; |
Only functions of type int -> 'a
| apply_to_int (fun x -> x +. 3) 4 |
Map and Fold
Common and useful HOFs exist
| let rec map f l = match l with |
| []-> [] |
| |h::t -> (f h)::(map f t) |
map: ('a -> 'b) -> 'a list -> 'b list
- take in a function and a list
- The list can be thought as the domain
- the function is applied to each item in the domain
- Returns new list of corresponding output
- Basically maps domain to co-domain
Map and Fold
Basically maps domain to co-domain
| let rec map f l = match l with |
| []-> [] |
| |h::t -> (f h)::(map f t) |
| (* map.ml *) |
| let add1 x = x + 1 |
| let x2 x = x + x |
| let is_even x = x mod 2 = 0 |
| let lst = [1 |
| map add1 lst |
| map x2 lst |
| map is_even lst |
| let fs = [add1 |
| map (fun f -> map f lst) fs |
| (* map.ml *) |
| let add1 x = x + 1 |
| let x2 x = x + x |
| let is_even x = x mod 2 = 0 |
| let lst = [1 |
| map add1 lst |
| map x2 lst |
| map is_even lst |
| let fs = [add1 |
| map (fun f -> map f lst) fs |
| (* map.ml *) |
| let add1 x = x + 1 |
| let x2 x = x + x |
| let is_even x = x mod 2 = 0 |
| let lst = [1 |
| map add1 lst |
| map x2 lst |
| map is_even lst |
| let fs = [add1 |
| map (fun f -> map f lst) fs |
Map and Fold
Consider the following family of functions
| |
| let rec concat lst = match lst with |
| []-> "" |
| |h::t -> h^(concat t) |
| |
| let rec sum lst = match lst with |
| []-> 0 |
| |h::t -> h+(sum t) |
| |
| let rec product lst = match lst with |
| []-> 1 |
| |h::t -> h*(productt) |
| |
| let rec length lst = match lst with |
| []-> 0 |
| |_::t -> 1+(length t) |
| |
| let rec rev lst = match lst with |
| []-> [] |
| |h::t -> (rev t) @ [h];; |
| |
| let rec filter lst compare_fun = match lst with |
| []-> [] |
| |h::t -> if compare_fun h then |
| h::(filter t compare_fun) else |
| filter t compare_fun;; |
| |
| let rec concat lst = match lst with |
| []-> "" |
| |h::t -> h^(concat t) |
| |
| let rec sum lst = match lst with |
| []-> 0 |
| |h::t -> h+(sum t) |
| |
| let rec product lst = match lst with |
| []-> 1 |
| |h::t -> h*(productt) |
| |
| let rec length lst = match lst with |
| []-> 0 |
| |_::t -> 1+(length t) |
| |
| let rec rev lst = match lst with |
| []-> [] |
| |h::t -> (rev t) @ [h];; |
| |
| let rec filter lst compare_fun = match lst with |
| []-> [] |
| |h::t -> if compare_fun h then |
| h::(filter t compare_fun) else |
| filter t compare_fun;; |
| |
| let rec concat lst = match lst with |
| []-> "" |
| |h::t -> h^(concat t) |
| |
| let rec sum lst = match lst with |
| []-> 0 |
| |h::t -> h+(sum t) |
| |
| let rec product lst = match lst with |
| []-> 1 |
| |h::t -> h*(productt) |
| |
| let rec length lst = match lst with |
| []-> 0 |
| |_::t -> 1+(length t) |
| |
| let rec rev lst = match lst with |
| []-> [] |
| |h::t -> (rev t) @ [h];; |
| |
| let rec filter lst compare_fun = match lst with |
| []-> [] |
| |h::t -> if compare_fun h then |
| h::(filter t compare_fun) else |
| filter t compare_fun;; |
| |
| let rec concat lst = match lst with |
| []-> "" |
| |h::t -> h^(concat t) |
| |
| let rec sum lst = match lst with |
| []-> 0 |
| |h::t -> h+(sum t) |
| |
| let rec product lst = match lst with |
| []-> 1 |
| |h::t -> h*(productt) |
| |
| let rec length lst = match lst with |
| []-> 0 |
| |_::t -> 1+(length t) |
| |
| let rec rev lst = match lst with |
| []-> [] |
| |h::t -> (rev t) @ [h];; |
| |
| let rec filter lst compare_fun = match lst with |
| []-> [] |
| |h::t -> if compare_fun h then |
| h::(filter t compare_fun) else |
| filter t compare_fun;; |
| |
| let rec concat lst = match lst with |
| []-> "" |
| |h::t -> h^(concat t) |
| |
| let rec sum lst = match lst with |
| []-> 0 |
| |h::t -> h+(sum t) |
| |
| let rec product lst = match lst with |
| []-> 1 |
| |h::t -> h*(productt) |
| |
| let rec length lst = match lst with |
| []-> 0 |
| |_::t -> 1+(length t) |
| |
| let rec rev lst = match lst with |
| []-> [] |
| |h::t -> (rev t) @ [h];; |
| |
| let rec filter lst compare_fun = match lst with |
| []-> [] |
| |h::t -> if compare_fun h then |
| h::(filter t compare_fun) else |
| filter t compare_fun;; |
| |
| let rec concat lst = match lst with |
| []-> "" |
| |h::t -> h^(concat t) |
| |
| let rec sum lst = match lst with |
| []-> 0 |
| |h::t -> h+(sum t) |
| |
| let rec product lst = match lst with |
| []-> 1 |
| |h::t -> h*(productt) |
| |
| let rec length lst = match lst with |
| []-> 0 |
| |_::t -> 1+(length t) |
| |
| let rec rev lst = match lst with |
| []-> [] |
| |h::t -> (rev t) @ [h];; |
| |
| let rec filter lst compare_fun = match lst with |
| []-> [] |
| |h::t -> if compare_fun h then |
| h::(filter t compare_fun) else |
| filter t compare_fun;; |
| |
| let rec concat lst = match lst with |
| []-> "" |
| |h::t -> h^(concat t) |
| |
| let rec sum lst = match lst with |
| []-> 0 |
| |h::t -> h+(sum t) |
| |
| let rec product lst = match lst with |
| []-> 1 |
| |h::t -> h*(productt) |
| |
| let rec length lst = match lst with |
| []-> 0 |
| |_::t -> 1+(length t) |
| |
| let rec rev lst = match lst with |
| []-> [] |
| |h::t -> (rev t) @ [h];; |
| |
| let rec filter lst compare_fun = match lst with |
| []-> [] |
| |h::t -> if compare_fun h then |
| h::(filter t compare_fun) else |
| filter t compare_fun;; |
Aggregates a list to a single value
Map and Fold
Consider the following Fibinocci
| |
| let rec fib n = |
| if n < 2 then 1 else (fib (n-1)) - (fib (n-2));; |
- imperfect compiler: too many stack frames
- Not tail Recursive
Let's fix this
| |
| let rec fib n a b = |
| if n = 0 then a else fib (n-1) (a+b) a;; |
Map and Fold
Fold will incorporate
- Aggregating a list to a single value
- Reducing Stack Frames
| |
| let rec fold f a l= match l with |
| []-> a |
| |h::t-> fold f (f a h) t;; |
fold: ('a -> 'b -> 'a) -> 'a -> 'b list -> 'a
Map and Fold
Foldr only uses
- Aggregating a list to a single value
But, the order of evaluation is reversed
| |
| let rec foldr f l a = match l with |
| []-> a |
| |h::t-> f h (foldr f t a);; |
foldr: ('b -> 'a -> 'a) -> 'b list -> 'a -> 'a
Map and Fold
| |
| let rec fold f a l= match l with |
| []-> a |
| |h::t-> fold f (f a h) t;; |
| |
| let rec foldr f l a = match l with |
| []-> a |
| |h::t-> f h (foldr f t a);; |
Be careful with non-commutative functions
let diff x y = x - y in
(fold diff 0 [1;2;3]) = (foldr diff [1;2;3] 0);;
Map and Fold
let rec fold f a l = match l with
[]-> a
|h::t-> fold f (f a h) t
(* fold.ml *)
let concat a h = a^h;;
let sum a h = a + h;;
let product a h = a * h;;
let length a _ = a + 1;;
let rev a h = a @ [h];;
let filter f lst =
let filter_helper a h = if f h then h::a else a in
fold filter_helper [] lst;;
let is_even x = x mod 2 = x;;
filter is_even [1;2;3;4;5];;
Map and Fold
We can use map and fold together for cool stuff
Can we count 1s in a 2d matrix?
let countones lst =
let get1s lst = filter (fun x -> x = 1) lst in
let ones = map get1s lst in
let counts = map (fold length 0) ones in
let total = fold sum 0 counts in total;;
val countones : int list list -> int =
let count1 lst = fold (fun a h -> if h = 1 then a+1 else a) 0 lst;;
let count1s lst = fold (+) 0 (map count1 lst)
How could we rotate a matrix?