Ocaml Tutorial
Ocaml Tutorial
INF549
http://www.enseignement.polytechnique.fr/profs/
informatique/Jean-Christophe.Filliatre/INF549/
questions ⇒ Jean-Christophe.Filliatre@lri.fr
hello.ml
compiling
% ocamlopt -o hello hello.ml
executing
% ./hello
hello world!
hello.ml
compiling
% ocamlopt -o hello hello.ml
executing
% ./hello
hello world!
hello.ml
compiling
% ocamlopt -o hello hello.ml
executing
% ./hello
hello world!
let x = 1 + 2;;
print_int x;;
let y = x * x;;
print_int y;;
let x = 1 + 2;;
print_int x;;
let y = x * x;;
print_int y;;
Java OCaml
final int x = 42; let x = 42
for loop
for i = 1 to 10 do x := !x + i done
sequence
x := 1; 2 * !x
for loop
for i = 1 to 10 do x := !x + i done
sequence
x := 1; 2 * !x
for loop
for i = 1 to 10 do x := !x + i done
sequence
x := 1; 2 * !x
for loop
for i = 1 to 10 do x := !x + i done
sequence
x := 1; 2 * !x
incorrect:
2 + (if !x > 0 then 1)
incorrect:
2 + (if !x > 0 then 1)
incorrect:
2 + (if !x > 0 then 1)
let x = e1 in e2 is an expression
its type and value are those of e2,
in an environment where x has the type and value of e1
example
let x = 1 in (let y = 2 in x + y) * (let z = 3 in x * z)
let x = e1 in e2 is an expression
its type and value are those of e2,
in an environment where x has the type and value of e1
example
let x = 1 in (let y = 2 in x + y) * (let z = 3 in x * z)
let x = e1 in e2 is an expression
its type and value are those of e2,
in an environment where x has the type and value of e1
example
let x = 1 in (let y = 2 in x + y) * (let z = 3 in x * z)
Java OCaml
{ int x = 1; let x = ref 1 in
x = x + 1; x := !x + 1;
int y = x * x; let y = !x * !x in
System.out.print(y); } print int y
# let x = 1 in x + 2;;
- : int = 3
# let y = 1 + 2;;
val y : int = 3
# y * y;;
- : int = 9
# let f x = x * x;;
# f 4;;
- : int = 16
# let f x = x * x;;
# f 4;;
- : int = 16
# let f x = x * x;;
# f 4;;
- : int = 16
# let f x = x * x;;
# f 4;;
- : int = 16
Java OCaml
static int f(int x) { let f x =
return x * x; x * x
}
example
# let x = ref 1;;
# let set v = x := v;;
# set 3;;
- : unit = ()
# !x;;
- : int = 3
Jean-Christophe Filliâtre A Short Introduction to OCaml INF549 19 / 102
procedure
a procedure = a function whose result type is unit
example
# let x = ref 1;;
# let set v = x := v;;
# set 3;;
- : unit = ()
# !x;;
- : int = 3
Jean-Christophe Filliâtre A Short Introduction to OCaml INF549 19 / 102
procedure
a procedure = a function whose result type is unit
example
# let x = ref 1;;
# let set v = x := v;;
# set 3;;
- : unit = ()
# !x;;
- : int = 3
Jean-Christophe Filliâtre A Short Introduction to OCaml INF549 19 / 102
procedure
a procedure = a function whose result type is unit
example
# let x = ref 1;;
# let set v = x := v;;
# set 3;;
- : unit = ()
# !x;;
- : int = 3
Jean-Christophe Filliâtre A Short Introduction to OCaml INF549 19 / 102
function without arguments
example
# let reset () = x := 0;;
# reset ();;
example
# let reset () = x := 0;;
# reset ();;
# f 1 2 3;;
- : int = 3
# f 1 2 3;;
- : int = 3
- : bool = true
val pythagorean : int -> int -> int -> bool = <fun>
- : bool = true
val pythagorean : int -> int -> int -> bool = <fun>
- : int = 4
internally
let f x = x+1;;
is identical to
let f = fun x -> x+1;;
- : int = 4
internally
let f x = x+1;;
is identical to
let f = fun x -> x+1;;
# g 4;;
- : int = 25
Jean-Christophe Filliâtre A Short Introduction to OCaml INF549 24 / 102
partial application
fun x y -> x*x + y*y
is the same as
fun x -> fun y -> x*x + y*y
one can apply a function partially
example
# let f x y = x*x + y*y;;
# g 4;;
- : int = 25
Jean-Christophe Filliâtre A Short Introduction to OCaml INF549 24 / 102
partial application
# c ();;
- : int = 0
# c ();;
- : int = 1
Jean-Christophe Filliâtre A Short Introduction to OCaml INF549 26 / 102
higher-order functions
a function may take functions as arguments
# let integral f =
let n = 100 in
let s = ref 0.0 in
for i = 0 to n-1 do
let x = float i /. float n in s := !s +. f x
done;
!s /. float n
# integral sin;;
- : float = 0.455486508387318301
- : float = 0.32835
Jean-Christophe Filliâtre A Short Introduction to OCaml INF549 27 / 102
iteration
for (Elt x: s) {
... do something with x ...
}
example
iter (fun x -> Printf.printf "%s\n" x) s
for (Elt x: s) {
... do something with x ...
}
example
iter (fun x -> Printf.printf "%s\n" x) s
example:
let zero f =
let rec lookup i = if f i = 0 then i else lookup (i+1) in
lookup 0
example:
let zero f =
let rec lookup i = if f i = 0 then i else lookup (i+1) in
lookup 0
- : int = 3
# f true;;
- : bool = true
# f print_int;;
# f print_int 1;;
1- : unit = ()
Jean-Christophe Filliâtre A Short Introduction to OCaml INF549 31 / 102
polymorphism
# let f x = x;;
- : int = 3
# f true;;
- : bool = true
# f print_int;;
# f print_int 1;;
1- : unit = ()
Jean-Christophe Filliâtre A Short Introduction to OCaml INF549 31 / 102
polymorphism
example:
# let compose f g = fun x -> f (g x);;
val compose : (’a -> ’b) -> (’c -> ’a) -> ’c -> ’b = <fun>
example:
# let compose f g = fun x -> f (g x);;
val compose : (’a -> ’b) -> (’c -> ’a) -> ’c -> ’b = <fun>
benefits:
unused memory is reclaimed automatically
efficient allocation
benefits:
unused memory is reclaimed automatically
efficient allocation
# a.(1);;
- : int = 2
- : unit = ()
# a;;
# a.(1);;
- : int = 2
- : unit = ()
# a;;
Java OCaml
int[] a = new int[42]; let a = Array.make 42 0
a[17] a.(17)
a.length Array.length a
let insertion_sort a =
let swap i j =
let t = a.(i) in a.(i) <- a.(j); a.(j) <- t
in
for i = 1 to Array.length a - 1 do
(* insert element a[i] in a[0..i-1] *)
let j = ref (i - 1) in
while !j >= 0 && a.(!j) > a.(!j + 1) do
swap !j (!j + 1); decr j
done
done
let insertion_sort a =
let swap i j =
let t = a.(i) in a.(i) <- a.(j); a.(j) <- t
in
for i = 1 to Array.length a - 1 do
(* insert element a[i] in a[0..i-1] *)
let rec insert j =
if j >= 0 && a.(j) > a.(j+1) then
begin swap j (j+1); insert (j-1) end
in
insert (i-1)
done
# x.im;;
- : float = -1.
# x.im;;
- : float = -1.
# x.im;;
- : float = -1.
- : unit = ()
# p.age;;
- : int = 24
- : unit = ()
# p.age;;
- : int = 24
Java OCaml
class T { type t = {
final int v; boolean b; v: int;
T(int v, boolean b) { mutable b: bool;
this.v = v; this.b = b; }
}
}
r.v r.v
access to components
# let (a,b,c,d) = v;;
val a : int = 1
val b : bool = true
val c : string = "hello"
val d : char = ’a’
Jean-Christophe Filliâtre A Short Introduction to OCaml INF549 44 / 102
tuples
usual notation
# (1,2,3);;
access to components
# let (a,b,c,d) = v;;
val a : int = 1
val b : bool = true
val c : string = "hello"
val d : char = ’a’
Jean-Christophe Filliâtre A Short Introduction to OCaml INF549 44 / 102
tuples
useful to return several values
# let rec division n m =
if n < m then (0, n)
else let (q,r) = division (n - m) m in (q + 1, r);;
# f (1,2);;
- : int = 3
Jean-Christophe Filliâtre A Short Introduction to OCaml INF549 45 / 102
tuples
useful to return several values
# let rec division n m =
if n < m then (0, n)
else let (q,r) = division (n - m) m in (q + 1, r);;
# f (1,2);;
- : int = 3
Jean-Christophe Filliâtre A Short Introduction to OCaml INF549 45 / 102
lists
# let l = 1 :: 2 :: 3 :: [];;
shorter syntax
# let l = [1; 2; 3];;
# sum [1;2;3];;
- : int = 6
# sum [1;2;3];;
- : int = 6
# sum [1;2;3];;
- : int = 6
1 2 3 []
# True;;
- : fmla = True
lists predefined as
type ’a list = [] | :: of ’a * ’a list
Jean-Christophe Filliâtre A Short Introduction to OCaml INF549 49 / 102
algebraic data types
lists = particular case of algebraic data type
# True;;
- : fmla = True
lists predefined as
type ’a list = [] | :: of ’a * ’a list
Jean-Christophe Filliâtre A Short Introduction to OCaml INF549 49 / 102
algebraic data types
lists = particular case of algebraic data type
# True;;
- : fmla = True
lists predefined as
type ’a list = [] | :: of ’a * ’a list
Jean-Christophe Filliâtre A Short Introduction to OCaml INF549 49 / 102
algebraic data types
lists = particular case of algebraic data type
# True;;
- : fmla = True
lists predefined as
type ’a list = [] | :: of ’a * ’a list
Jean-Christophe Filliâtre A Short Introduction to OCaml INF549 49 / 102
pattern matching
one may write let pattern = expression when there is a single pattern
(as in let (a,b,c,d) = v for instance)
one may write let pattern = expression when there is a single pattern
(as in let (a,b,c,d) = v for instance)
allocation is cheap
memory is reclaimed automatically
allocated values are necessarily initialized
most values cannot be mutated
(only arrays and mutable record fields can be)
efficient representation of values
pattern matching = case analysis over values
a value is
either a primitive value (integer, floating point, Boolean, [], etc.)
or a pointer (to an array, a constructor such as And, etc.)
it fits on 64 bits
it is exactly as in Java
- : bool = false
as in Java
- : bool = true
it is equivalent to equals in Java (when suitably defined)
usual notion
an exception may be raised
let division n m =
if m = 0 then raise Division_by_zero else ...
usual notion
an exception may be raised
let division n m =
if m = 0 then raise Division_by_zero else ...
usual notion
an exception may be raised
let division n m =
if m = 0 then raise Division_by_zero else ...
try
let v = Hashtbl.find table key in
...
with Not_found ->
...
(where Java typically returns null)
% ocamlopt -c main.ml
% ocamlopt -c main.ml
% ocamlopt -c main.ml
% ocamlopt -c main.ml
% ocamlopt -c main.ml
% ocamlopt -c arith.mli
% ocamlopt -c arith.ml
% ocamlopt -c main.ml
File "main.ml", line 2, characters 33-41:
Unbound value Arith.pi
% ocamlopt -c arith.mli
% ocamlopt -c arith.ml
% ocamlopt -c main.ml
File "main.ml", line 2, characters 33-41:
Unbound value Arith.pi
% ocamlopt -c arith.mli
% ocamlopt -c arith.ml
% ocamlopt -c main.ml
File "main.ml", line 2, characters 33-41:
Unbound value Arith.pi
% ocamlopt -c arith.mli
% ocamlopt -c arith.ml
% ocamlopt -c main.ml
File "main.ml", line 2, characters 33-41:
Unbound value Arith.pi
the compilation of a file only depends on the interfaces of the other files
⇒ fewer recompilation when a code changes but its interface does not
the compilation of a file only depends on the interfaces of the other files
⇒ fewer recompilation when a code changes but its interface does not
module A = struct
let a = 2
module B = struct
let b = 3
let f x = a * b * x
end
let f x = B.f (x + 1)
end
module A = struct
let a = 2
module B = struct
let b = 3
let f x = a * b * x
end
let f x = B.f (x + 1)
end
module A = struct
let a = 2
module B = struct
let b = 3
let f x = a * b * x
end
let f x = B.f (x + 1)
end
# M.a;;
# M.a;;
# M.a;;
# M.a;;
- : unit = ()
# Hint.add t 173;;
- : unit = ()
Jean-Christophe Filliâtre A Short Introduction to OCaml INF549 76 / 102
functor use
module Int = struct
type elt = int
let hash x = abs x
let eq x y = x=y
end
- : unit = ()
# Hint.add t 173;;
- : unit = ()
Jean-Christophe Filliâtre A Short Introduction to OCaml INF549 76 / 102
functor use
module Int = struct
type elt = int
let hash x = abs x
let eq x y = x=y
end
- : unit = ()
# Hint.add t 173;;
- : unit = ()
Jean-Christophe Filliâtre A Short Introduction to OCaml INF549 76 / 102
parallel
Java OCaml
interface HashedType<T> { module type HashedType = sig
type elt
int hash(); val hash: elt -> int
boolean eq(T x); val eq: elt -> elt -> bool
} end
module Dijkstra
(G: sig
type graph
type vertex
val succ: graph -> vertex -> (vertex * float) list
end) :
sig
val shortest_path:
G.graph -> G.vertex -> G.vertex -> G.vertex list * float
end
said otherwise:
a value is not modified by an operation,
but a new value is returned
let l = [1; 2; 3]
let l’ = 0 :: l
l’ l
0 1 2 3 []
l
1 2 3 0 []
let l = [1; 2; 3]
let l’ = [4; 5]
let l’’ = append l l ’
l l’
1 2 3 [] 4 5 []
l’’
1 2 3
let l = [1; 2; 3]
let l’ = [4; 5]
let l’’ = append l l ’
l l’
1 2 3 [] 4 5 []
l’’
1 2 3
let l = [1; 2; 3]
let l’ = [4; 5]
let l’’ = append l l ’
l l’
1 2 3 [] 4 5 []
l’’
1 2 3
12
12
20
20
42
1 correctness of programs
code is simpler
mathematical reasoning is possible
1 correctness of programs
code is simpler
mathematical reasoning is possible
example:
int x = 1;
int z = 2;
if (x == z) {
int y = 2;
if (y == z) return y; else return z;
} else
return x;
let us check that any variable which is used was previously declared
(within a list of statements)
immutable ⇒ persistent
type ’a t
val create : unit -> ’a t
val push : ’a -> ’a t -> ’a t
exception Empty
val pop : ’a t -> ’a * ’a t
input
6 5 4 []
output
1 2 3 []
exception Empty
when accessing several times the same queue whose second list is empty,
we reverse several times the same list
let’s add a reference to register the list reversal the first time it is
performed
type ’a t = (’a list * ’a list) ref
the side effect is done “under the hood”, in a way not observable from the
user, the contents of the queue staying the same
exception Empty
exception Empty