Recall Code blocks and Procs in Ruby
p = Proc.new {|x| x + 1}
We can pass procs in as arguments
p = Proc.new {|x| x + 1}
def f(x)
puts x.call(3)
end
Treating code and functions as data
We can do this and more in OCaml
Anonymous function: function not bound to a variable
Syntax: fun x1 ... xn -> e
fun x -> x + 3
Technically functions are anonymous functions with syntactic sugar
let add3 = fun x -> x + 3
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;;
Can pass in functions as arguments
(* function_application.ml *)
let apply f x = f x;;
(* type syntax: ('a -> 'b) -> 'a -> 'b *)
let sub3 x = x - 3;;
apply_to_int add3 4;;
apply_to_int sub3 4;;
Recall Functions have types
(* function_types.ml *)
let apply_to_int f x = f (x+1);;
Only functions of type int -> 'a
apply_to_int (fun x -> x +. 3) 4 (* error *)
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
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;2;3];;
map add1 lst;;
map x2 lst;;
map is_even lst;;
let fs = [add1;x2;(fun x -> -x)]
map (fun f -> map f lst) fs;;
Consider the following family of functions
(* ff.ml *)
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
Consider the following Fibinocci
(* fib.ml *)
let rec fib n =
if n < 2 then 1 else (fib (n-1)) - (fib (n-2));;
Let's fix this
(* fib-1.ml *)
let rec fib n a b =
if n = 0 then a else fib (n-1) (a+b) a;;
Fold will incorporate
(* fold.ml *)
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
Foldr only uses
But, the order of evaluation is reversed
(* foldr.ml *)
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
(* fold.ml *)
let rec fold f a l= match l with
[]-> a
|h::t-> fold f (f a h) t;;
(* foldr.ml *)
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);;
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];;
We can use map and fold together for cool stuff
Can we count 1s in a 2d matrix?
(* count 1s in a 2d matrix *)
(* based on what we already have (inefficent) *)
let countones lst =
(* take out non-ones from 1-d list *)
let get1s lst = filter (fun x -> x = 1) lst in
(* take out non-ones from each sublist *)
let ones = map get1s lst in
(* get the length of each 1 list *)
let counts = map (fold length 0) ones in
(* add up the lengths *)
let total = fold sum 0 counts in total;;
val countones : int list list -> int =
(* or we can do the easy way *)
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?