Let us start with a C example:
double avg(int x, int y) {
double z = (double)(x + y);
z = z/2;
printf("Answer is %g\n", z);
return z;
}
OCaml version:
let avg (x:int) (y:int) : float = begin
let z = float_of_int(x + y) in
let z = z /. 2.0 in
printf "Answer is %g\n" z;
z
end
Example 1:
let x = (22, 58) in (* tuple creation *)
...
let y, z = x in (* tuple field extraction *)
printf "first element is %d\n" y;
...
Example 2:
let add_points p1 p2 =
let x1, y1 = p1 in
let x2, y2 = p2 in
(x1 + x2, y1 + y2)
[]
[ element ]
[ e1; e2; e3]
x :: [y;z]
= [x;y;z]
[w;x] @ [y;z]
= [w;x;y;z]
Simple functional set (built out of lists)
let rec add_elem (s, e) =
if s = [] then [e]
else if List.hd s = e then s
else List.hd s :: add_elem(List.tl s, e)
Pattern matching version
let rec add_elem (s, e) = match s with
| [] -> [e]
| hd :: tl when e = hd -> s
| hd :: tl -> hd :: add_elem(tl, e)
C version; more cases to handle
List* add_elem(List *s, item e) {
if (s == NULL) {
return list(e, NULL);
}
else if (s->hd == e) {
return s;
}
else if (s->tl == NULL) {
s->tl = list(e, NULL);
return s;
}
else {
return add_elem(s->tl, e);
}
}
Type inference
let rec add_elem (s, e) = match s with
| [] -> [e]
| hd :: tl when e = hd -> s
| hd :: tl -> hd :: add_elem(tl, e)
val add_elem : 'a list * 'a -> 'a list
'a list
means List<T>
(exp : type)
exp
has type type
Simplifies Code (elimates if, accessors)
type btree = (* binary tree of strings *)
| Node of btree * string * btree
| Leaf of string
let rec height tree = match tree with with
| Leaf _ -> 1
| Node(x, _, y) -> 1 + max (height x) (height y)
let rec mem tree elt = match tree with
| Leaf str -> str = elt
| Node(x,str,y) -> str = elt || mem x elt || mem y elt
What if I forget a case?
let rec is_odd x = match x with
| 0 -> false
| 2 -> false
| x when x > 2 -> is_odd(x-2)
Message
Warning 8: this pattern-matching is not exhaustive.
Here is an example of a case that is not matched:
1
Functions and type type inference are polymorphic
Operate on more than one type
let rec length x = match x with
| [] -> 0
| hd :: tl -> 1 + length tl
val length: 'a list -> int
'a
means “any one type”let rec map f lst = match lst with
| [] -> []
| hd :: tl -> f hd :: map f tl
val map : ('a -> 'b) -> 'a -> 'b list
length
and map
sum [1; 5; 8]
= 14
product [1; 5; 8]
= 40
and [true; true; false]
= false
or [true; true; false]
= true
filter (fun x -> x > 4) [1; 5; 8]
= [5; 8]
reverse [1; 5; 8]
= [8; 5; 1]
mem 5 [1; 5; 8]
= true
The fold
operator comes from Recursion Theory (Kleene, 1952)
let rec fold f acc lst = match lst with
| [] -> acc
| hd :: tl -> fold f (f acc hd) tl
val fold: ('a -> 'b -> 'a) -> 'a -> 'b list -> 'a
Imagine we are summing a list: f
is addition
fold
length lst = fold (fun acc elt -> acc + 1) 0 lst
sum lst = fold (fun acc elt -> acc + elt) 0 lst
product lst = fold (fun acc elt -> acc * elt) 1 lst
and lst = fold (fun acc elt -> acc & elt) true lst
or
or reverse
with fold
?reverse lst = fold (fun acc e -> acc @ [e]) [] lst
filter keep_it lst = fold (fun acc elt -> if keep_it elt then elt :: acc else acc) [] lst
mem wanted lst = fold (fun acc elt -> acc || wanted = elt) false lst
let map f lst = fold (fun acc -> elt -> (f elt) :: acc) [] lst
f : 'a -> 'b
lst : 'a list
acc : 'b list
elt : 'a
Currying: “if you fix some arguments, then you get a function of the remaining arguments”
Example:
let myadd x y = x + y
val myadd : int -> int -> int
let addtwo = myadd 2
val addtwo : int -> int
addtwo 77 = 79
Example:
let y = 55
let f x = x + y
f 3 --> means --> 3 + y --> means --> 3 + 55
let rec insert_sort cmp lst =
match lst with
| [] -> []
| hd :: tl -> insert cmp hd (insert_sort cmp tl)
and insert cmp elt lst =
match lst with
| [] -> [elt]
| hd :: tl when cmp hd elt -> hd :: (insert cmp elt tl)
| _ -> elt :: lst
sort
type: (sort : ('a * 'a -> bool) -> 'a list -> 'a list
Examples:
langs = ["fortran"; "algol"; "c"]
sort (fun a b -> a < b) langs
sort (fun a b -> a > b) langs
sort fun a b -> strlen a < strlen b) langs
fold
is a powerful and general higher-order function.