Author: Christian.Queinnec@lip6.fr

## Parameterized Modules

Parameterized modules are to modules what functions are to base values. Just like a function returns a new value from the values of its parameters, a parameterized module builds a new module from the modules given as parameters. Parameterized modules are also called functors.
The addition of functors to the module language increases the opportunities for code reuse in structures.
Functors are defined using a function-like syntax:

### Syntax

functor ( Name : signature ) -> structure

    # module Couple = functor ( Q : sig type t end ) ->
       struct type couple = Q.t * Q.t end ;;
    module Couple :
      functor(Q : sig type t end) -> sig type couple = Q.t * Q.t end

As for functions, syntactic sugar is provided for defining and naming a functor:

### Syntax

module Name1 ( Name2 : signature ) = structure

    # module Couple ( Q : sig type t end ) =  struct type couple = Q.t * Q.t end ;;
    module Couple :
      functor(Q : sig type t end) -> sig type couple = Q.t * Q.t end

A functor can take several parameters:

### Syntax

functor ( Name1 : signature1 ) -> :
functor ( Namen : signaturen ) -> structure

The syntactic sugar for defining and naming a functor extends to multiple-argument functors:

### Syntax

module Name (Name1 : signature1 ) ...( Namen : signaturen ) =
structure

The application of a functor to its arguments is written thus:

### Syntax

module Name = functor ( structure1 ) ...( structuren )

Note that each parameter is written between parentheses. The result of the application can be either a simple module or a partially applied functor, depending on the number of parameters of the functor.

### Warning

There is no equivalent to functors at the level of signature: it is not possible to build a signature by application of a ``functorial signature'' to other signatures.

A closed functor is a functor that does not reference any module except its parameters. Such a closed functor makes its communications with other modules entirely explicit. This provides maximal reusability, since the modules it references are determined at application time only. There is a strong parallel between a closed function (without free variables) and a closed functor.

### Functors and Code Reuse

The Objective CAML standard library provides three modules defining functors. Two of them take as argument a module implementing a totally ordered data type, that is, a module with the following signature:

    # module type OrderedType =
       sig
         type t
         val compare: t -> t -> int
       end ;;
    module type OrderedType = sig type t val compare : t -> t -> int end

Function `compare` takes two arguments of type `t` and returns a negative integer if the first is less than the second, zero if both are equal, and a positive integer if the first is greater than the second. Here is an example of totally ordered type: pairs of integers equipped with lexicographic ordering.

    # module OrderedIntPair =
       struct
         type t = int * int
         let compare (x1,x2) (y1,y2) =
           if x1 < y1 then -1
           else if x1 > y1 then 1
           else if x2 < y2 then -1
           else if x2 > y2 then 1
           else 0
       end ;;
    module OrderedIntPair :
      sig type t = int * int val compare : 'a * 'b -> 'a * 'b -> int end

The functor `Make` from module `Map` returns a module that implements association tables whose keys are values of the ordered type passed as argument. This module provides operations similar to the operations on association lists from module `List`, but using a more efficient and more complex data structure (balanced binary trees).

    # module AssocIntPair = Map.Make (OrderedIntPair) ;;
    module AssocIntPair :
      sig
        type key = OrderedIntPair.t
        and 'a t = 'a Map.Make(OrderedIntPair).t
        val empty : 'a t
        val add : key -> 'a -> 'a t -> 'a t
        val find : key -> 'a t -> 'a
        val remove : key -> 'a t -> 'a t
        val mem : key -> 'a t -> bool
        val iter : (key -> 'a -> unit) -> 'a t -> unit
        val map : ('a -> 'b) -> 'a t -> 'b t
        val fold : (key -> 'a -> 'b -> 'b) -> 'a t -> 'b -> 'b
      end

The `Make` functor allows to construct association tables over any key type for which we can write a `compare` function.
The standard library module `Set` also provides a functor named `Make` taking an ordered type as argument and returning a module implementing sets of sets of values of this type.

    # module SetIntPair = Set.Make (OrderedIntPair) ;;
    module SetIntPair :
      sig
        type elt = OrderedIntPair.t
        and t = Set.Make(OrderedIntPair).t
        val empty : t
        val is_empty : t -> bool
        val mem : elt -> t -> bool
        val add : elt -> t -> t
        val singleton : elt -> t
        val remove : elt -> t -> t
        val union : t -> t -> t
        val inter : t -> t -> t
        val diff : t -> t -> t
        val compare : t -> t -> int
        val equal : t -> t -> bool
        val subset : t -> t -> bool
        val iter : (elt -> unit) -> t -> unit
        val fold : (elt -> 'a -> 'a) -> t -> 'a -> 'a
        val cardinal : t -> int
        val elements : t -> elt list
        val min_elt : t -> elt
        val max_elt : t -> elt
        val choose : t -> elt
      end

The type `SetIntPair.t` is the type of sets of integer pairs, with all the usual set operations provided in `SetIntPair`, including a set comparison function `SetIntPair.compare`. To illustrate the code reuse made possible by functors, we now build sets of sets of integer pairs.

    # module SetofSet = Set.Make (SetIntPair) ;;

    # let x = SetIntPair.singleton (1,2) ;;           (* x = { (1,2) }        *)
    val x : SetIntPair.t = <abstr>
    # let y = SetofSet.singleton SetIntPair.empty ;;  (* y = { {} }           *)
    val y : SetofSet.t = <abstr>
    # let z = SetofSet.add x y ;;                     (* z = { {(1,2)} ; {} } *)
    val z : SetofSet.t = <abstr>

The `Make` functor from module `Hashtbl` is similar to that from the `Map` module, but implements (imperative) hash tables instead of (purely functional) balanced trees. The argument to `Hashtbl.Make` is slightly different: in addition to the type of the keys for the hash table, it must provide an equality function testing the equality of two keys (instead of a full-fledged comparison function), plus a hash function, that is, a function associating integers to keys.

    # module type HashedType =
       sig
         type t
         val equal: t -> t -> bool
         val hash: t -> int
       end ;;
    module type HashedType =
      sig type t val equal : t -> t -> bool val hash : t -> int end
    # module IntMod13 =
       struct
         type t = int
         let equal = (=)
         let hash x = x mod 13
       end ;;
    module IntMod13 :
      sig type t = int val equal : 'a -> 'a -> bool val hash : int -> int end
    # module TblInt = Hashtbl.Make (IntMod13) ;;
    module TblInt :
      sig
        type key = IntMod13.t
        and 'a t = 'a Hashtbl.Make(IntMod13).t
        val create : int -> 'a t
        val clear : 'a t -> unit
        val add : 'a t -> key -> 'a -> unit
        val remove : 'a t -> key -> unit
        val find : 'a t -> key -> 'a
        val find_all : 'a t -> key -> 'a list
        val mem : 'a t -> key -> bool
        val iter : (key -> 'a -> unit) -> 'a t -> unit
      end

### Local Module Definitions

The Objective CAML core language allows a module to be defined locally to an expression.

### Syntax

let module Name = structure
in expr

For instance, we can use the `Set` module locally to write a sort function over integer lists, by inserting each list element into a set and finally converting the set to the sorted list of its elements.

    # let sort l =
       let module M =
          struct
            type t = int
            let compare x y =
              if x < y then -1 else if x > y then 1 else 0
          end
      in
        let module MSet = Set.Make(M)
        in  MSet.elements (List.fold_right MSet.add l MSet.empty) ;;
    val sort : int list -> int list = <fun>

    # sort [ 5 ; 3 ; 8 ; 7 ; 2 ; 6 ; 1 ; 4 ] ;;
    - : int list = [1; 2; 3; 4; 5; 6; 7; 8]

Objective CAML does not allow a value to escape a `let module` expression if the type of the value is not known outside the scope of the expression.

    # let test =
       let module Foo =
         struct
           type t
           let id x = (x:t)
         end
       in Foo.id ;;
    Characters 15-101:
    This `let module' expression has type Foo.t -> Foo.t
    In this type, the locally bound module name Foo escapes its scope