The Ocaml module system
I've always been jealous of ML's module system
— Simon Peyton Jones
Typing with a colon
i : int
Type argument order
(** Also the constructor for list is double-colon *)
( :: ) : 'a -> 'a list -> 'a list
module Fixed = struct
let scale = 8
let of_int i = i lsl scale
let half = 1 lsl (scale - 1)
(* note: not the same (+). *)
let (+) = (+)
let ( * ) n p = (n*p) asr scale
end
module Fixed : sig
(** [of_int i] is [i] as a fixed point
number. *)
val of_int : int -> int
(** [half] is the number 1/2. *)
val half : int
(** [n+p] is the sum of [n] and [p], this
operation is exact. *)
val (+) : int -> int -> int
(** [n*p] is the product of [n] and [p],
rounded down. *)
val ( * ) : int -> int -> int
end
let x = Fixed.half
open Fixed
let y = half * half + (Fixed.of_int 1)
let scale = 8
let of_int i = i lsl scale
let half = 1 lsl (scale - 1)
(* note: not the same (+). *)
let (+) = (+)
let ( * ) n p = (n*p) asr scale
(** [of_int i] is [i] as a fixed point
number. *)
val of_int : int -> int
(** [half] is the number 1/2. *)
val half : int
(** [n+p] is the sum of [n] and [p], this
operation is exact. *)
val (+) : int -> int -> int
(** [n*p] is the product of [n] and [p],
rounded down. *)
val ( * ) : int -> int -> int
fixed.mli
fixed.ml
let x = Fixed.half
open Fixed
let y = half * half + (Fixed.of_int 1)
let scale = 8
let of_int i = i lsl scale
let half = 1 lsl (scale - 1)
(* note: not the same (+). *)
let (+) = (+)
let ( * ) n p = (n*p) asr scale
module Repr = struct
let integer_part n = n asr scale
let fractional_part n =
n land (lnot (-1 lsl scale))
end
val of_int : int -> int
val half : int
val (+) : int -> int -> int
val ( * ) : int -> int -> int
module Repr : sig
(** [integer_part n] is the integer part
of the fixed point number [n]. *)
val integer_part : int -> int
(** [fractional_part n] is the fractional
part of the fixed point number [n]
multiplied by 2^8.*)
val fractional_part : int -> int
end
fixed.mli
fixed.ml
let x =
Fixed.Repr.integer_part (Fixed.of_int 57)
open Fixed
let y = Repr.fractional_part (of_int 18)
open Fixed.Repr
let y = integral_part (Fixed.of_int 42)
type t = int
let scale = 8
let of_int i = i lsl scale
let half = 1 lsl (scale - 1)
(* note: not the same (+). *)
let (+) = (+)
let ( * ) n p = (n*p) asr scale
(** Fixed point numbers with scaling
factor 2^8*)
type t
(** [of_int i] is [i] as a fixed point
number. *)
val of_int : int -> t
(** [half] is the number 1/2. *)
val half : t
(** [n+p] is the sum of [n] and [p], this
operation is exact. *)
val (+) : t -> t -> t
(** [n*p] is the product of [n] and [p],
rounded down. *)
val ( * ) : t -> t -> t
fixed.mli
fixed.ml
let x : Fixed.t = Fixed.half
open Fixed
let y = half * half + (Fixed.of_int 1)
(** Fixed point numbers with scaling
factor 2^8*)
type t
(** [of_int i] is [i] as a fixed point
number. *)
val of_int : int -> t
(** [half] is the number 1/2. *)
val half : t
(** [n+p] is the sum of [n] and [p], this
operation is exact. *)
val (+) : t -> t -> t
(** [n*p] is the product of [n] and [p],
rounded down. *)
val ( * ) : t -> t -> t
fixed.mli
let y =
Fixed.(+)
(Fixed.(*)
Fixed.half
Fixed.half)
(Fixed.of_int 1)
let y =
Fixed.(half * half + (Fixed.of_int 1))
(* equivalently *)
let y =
let open Fixed in
half * half + (Fixed.of_int 1)
vs.
module type Scale = sig
(** Scaling factor for fixed point numbers
expressed as a binary logarithm. *)
val scale : int
end
module Make (S : Scale) : sig
(** Fixed point numbers with scaling
factor 2^8*)
type t
val of_int : int -> t
val half : t
val (+) : t -> t -> t
val ( * ) : t -> t -> t
end
fixed.ml
fixed.mli
So, I hear you like dependent types
module type Scale = sig
val scale : int
end
module Make (S : Scale) = struct
type t = int
let of_int i = i lsl S.scale
let half = 1 lsl (S.scale - 1)
let (+) = (+)
let ( * ) n p = (n*p) asr S.scale
end
module Fixed8 =
Fixed.Make(struct scale = 8 end)
let y =
Fixed8.(half * half + (Fixed8.of_int 1))
module type Integer = sig
type t
val of_int : int -> t
val (+) : t -> t -> t
val ( * ) : t -> t -> t
val (lsl) : t -> int -> t
val (asr) : t -> int -> t
…
module Carry : sig
val plus : t -> t -> bool*t
val times : t -> t -> t*t
end
end
module type Scale = sig
val scale : int
end
module Fixed (I : Integer) (S : Scale) : sig
(** Fixed point numbers with scaling
factor 2^8*)
type t
val of_int : int -> t
val half : t
val (+) : t -> t -> t
val ( * ) : t -> t -> t
end
module type Integer = …
module type Scale = …
module Fixed (I : Integer) (S : Scale) : sig
(** Fixed point numbers with scaling
factor 2^8*)
type t
val of_int : int -> t
val half : t
val (+) : t -> t -> t
val ( * ) : t -> t -> t
end
module Int : Integer
module DoubleInt (I : Integer) : Integer
module Fixed16 =
Fixed.Make
(DoubleInt(Int))
(struct scale = 16 end)
let y =
Fixed16.(half * half + (Fixed16.of_int 1))
(** Almost complete implementation *)
module type Integer = sig
type t
val of_int : int -> t
val (+) : t -> t -> t
val ( * ) : t -> t -> t
val (lsl) : t -> int -> t
val (asr) : t -> int -> t
…
module Carry : sig
val plus : t -> t -> bool*t
val times : t -> t -> t*t
end
end
module type Scale = sig
val scale : int
end
module Int : Integer = struct
type t = int
let of_int i = i
let (+) = (+)
let ( * ) = ( * )
let (lsl) = (lsl)
let (asr) = (asr)
module Carry = struct
let plus n p = …
let times n p = …
end
end
module DoubleInt (I : Integer) : Integer = struct
type t = I.t * I.t
let of_int i = I.(of_int 0, of_int i)
module Carry = struct
let plus (nh,nl) (ph,pl) =
let (carryl,low) = I.Carry.plus nl pl in
let (carryh,high) =
if carryl then
I.Carry.plus nh ph
else
let (carry,h) = I.Carry.plus nh ph in
(carry, I.(h + of_int 1))
in
(carryh, (high,low))
let (+) n p = snd (plus n p)
(* Karatsuba multiplication. *)
let times (nh,nl) (ph,pl) =
let h = I.Carry.times nh ph in
let l = I.Carry.times nl pl in
let (mc,(mh, ml)) =
plus
(I.Carry.times nh pl)
(I.Carry.times nl ph)
in
let mcw = I.of_int (if mc then 1 else 0) in
let (c,rl) = plus (ml,I.of_int 0) l in
let rh =
if c then
h + (mh, mcw)
else
h + (mh, mcw) + of_int 1
in
( rh , rl )
end
let (+) = Carry.(+)
let ( * ) n p = snd (Carry.times n p)
let (lsl) (nh,nl) k = …
let (asr) (nh,nl) k = …
…
end
module Fixed (I : Integer) (S : Scale) : sig
(** Fixed point numbers with scaling
factor 2^8*)
type t
val of_int : int -> t
val half : t
val (+) : t -> t -> t
val ( * ) : t -> t -> t
end = struct
type t = I.t
let of_int i = I.(of_int i lsl S.scale)
let half = I.(of_int 1 lsl (S.scale - 1))
let (+) = I.(+)
let ( * ) n p = I.((n*p) asr S.scale)
end
Research
Backpack: system of mixins at the library level
In 8.4