Most large programs are broken up into smaller components, to make the program easier to:
Understand
Maintain
Upgrade
Reuse
OCaml provides extremely powerful mechanisms for supporting modularity and code reuse.
Recall our implementation of sets as lists…
type 'a set = 'a list
let mem x s = List.mem x s
let add x s = if (mem x s) then s else x::s
let subset s1 s2 = List.for_all (fun x -> mem x s2) s1
let eq s1 s2 = (subset s1 s2) && (subset s2 s1)
let union s1 s2 = List.fold_left (fun acc x ->
if (mem x acc) then acc else (x::acc)) s1 s2
let intersect s1 s2 = List.fold_left
(fun acc x -> if (mem x s2) then (x::acc) else acc) [] s1
Putting in "lSet.ml"
creates the LSet namespace.
To prevent other programmers from interfering with our representation we can specify an interface:
% ocamlc –i lSet.ml > lSet.mli
type 'a set = 'a list
val emptyset : 'a list
val is_empty : 'a list -> bool
val mem : 'a -> 'a list -> bool
val add : 'a -> 'a list -> 'a list
val subset : 'a list -> 'a list -> bool
val eq : 'a list -> 'a list -> bool
val union : 'a list -> 'a list -> 'a list
val intersect : 'a list -> 'a list -> 'a list
val check_set : 'a list -> bool
This tells other modules and programs what’s in LSet.
Anything left out of the interface is inaccessible:
(* lSet.mli *)
type 'a set
val emptyset : 'a set
val is_empty : 'a set -> bool
val mem : 'a -> 'a set -> bool
val add : 'a -> 'a set -> 'a set
val subset : 'a set -> 'a set -> bool
val eq : 'a set -> 'a set -> bool
val union : 'a set -> 'a set -> 'a set
val intersect : 'a set -> 'a set -> 'a set
% ocamlc –c lSet.mli lSet.ml
The type 'a LSet.set
is abstract – it can only be accessed through functions in lSet.ml
An interface specifies the minimal requirements for a module:
File "unSet.ml", line 1:
Error: The implementation unSet.ml does not match the interface unSet.cmi:
The field `fold' is required but not provided
The field `intersect' is required but not provided
And the maximal external access to the module:
We might run into several kinds of errors when using interfaces:
Type errors occur when types are mismatched between the implementation and interface:
Try changing let add x s = x::s
to let add s x = x::s
in lSet.ml
unSet.ml
tree.ml
/tree.mli
.mli
first, then .ml
…cs2041.org