Modules & Signatures
math_utils.ml automatically defines module Math_utils:
20.1 Every file is a module
math_utils.ml automatically defines module Math_utils:
(* math_utils.ml *)
let square x = x * x
let cube x = x * x * x(* main.ml *)
let () = print_int (Math_utils.square 5)20.2 Explicit modules (structures)
module Counter = struct
type t = int
let zero = 0
let incr c = c + 1
let to_string = string_of_int
end
let c = Counter.(incr (incr zero)) (* local open *)20.3 Signatures (module types)
Outside the module, 'a ListStack.t is abstract — clients cannot see that it is a list. This is information hiding / encapsulation.
module type STACK = sig
type 'a t (* abstract type *)
exception Empty
val empty : 'a t
val is_empty : 'a t -> bool
val push : 'a -> 'a t -> 'a t
val pop : 'a t -> 'a * 'a t (* raises Empty *)
val size : 'a t -> int
end
module ListStack : STACK = struct
type 'a t = 'a list
exception Empty
let empty = []
let is_empty s = s = []
let push x s = x :: s
let pop = function [] -> raise Empty | x :: s -> (x, s)
let size = List.length
end20.4 Interface files .mli
stack.ml contains the implementation. Anything not in the .mli is private. Always write .mli files for libraries.
(** A functional stack. *)
type 'a t
val empty : 'a t
val push : 'a -> 'a t -> 'a t
val pop : 'a t -> ('a * 'a t) option20.5 Opening modules
open List (* global open: brings everything in scope (use sparingly) *)
let open List in map f xs (* local open *)
List.(map f xs) (* local open, compact *)
open! Base (* open, silencing shadowing warning *)
module L = List (* alias *)20.6 Nested modules
module Geometry = struct
module Point = struct
type t = { x : float; y : float }
let origin = { x = 0.; y = 0. }
end
module Circle = struct
type t = { center : Point.t; radius : float }
end
end
let p = Geometry.Point.origin20.7 include
module ExtList = struct
include List
let sum = fold_left ( + ) 0
end
module type EXT_STACK = sig
include STACK
val peek : 'a t -> 'a option
end20.8 Abstract types & smart constructors
Now every Email.t in the program is guaranteed to have been validated.
module Email : sig
type t
val of_string : string -> t option
val to_string : t -> string
end = struct
type t = string
let of_string s = if String.contains s '@' then Some s else None
let to_string s = s
end20.9 Private types
module Positive : sig
type t = private int (* readable as int, but only constructible via make *)
val make : int -> t option
end = struct
type t = int
let make n = if n > 0 then Some n else None
end
let f (p : Positive.t) = (p :> int) + 1 (* coercion to int allowed *)