Search code examples
moduleocamlfunctor

Ascribing multiple OCaml Signatures to a Module


Ocaml combining signatures

Suppose I have two signatures, Ordered, and Field

module type ORDERED = sig 
    type t
    type comparison = LT | EQ | GT
    val cmp : t -> t -> comparison
end

module type FIELD = sig
    type t
    val (+) : t -> t -> t
    val ( * ) : t -> t -> t
    val inv : t -> t
    val neg : t -> t
    val zero : t
    val one : t
end

And I want to make a functor that takes two Ordered Fields and produces another Ordered Field (say operations are applied component-wise and we use dictionary order for comparison). How would I specify that the "input modules" satisfy two signatures simultaneously?

Here is some strawman syntax for what I want to do:

module NaivePair = functor (Left : ORDERED & FIELD) (Right : ORDERED & FIELD) ->
    struct
        type t = Left.t * Right.t
        (* definitions *)
    end

It might be the case that there's an elegant way to take a "union" of signatures (but not an anonymous union), or create a wrapper module around concrete ORDERED and FIELD implementations that just happen to share a type t. I am curious what the idiomatic OCaml way to do what I am trying to achieve is.


Solution

  • Define a new module type using include and with type t := t:

    module type ORDERED_FIELD = sig
      include ORDERED
      include FIELD with type t := t
    end
    

    Without with type t := t, the definition is rejected since both ORDERED and FIELD declares the type of the same name. include FIELD with type t := t is to "substitute" t of FIELD by ORDERED.t.

    ocamlc -i -c x.ml to see what ORDERED_FIELD is exactly what you want:

    $ ocamlc -i -c x.ml
    ...
    ...
    module type ORDERED_FILED =
      sig
        type t
        type comparison = LT | EQ | GT
        val cmp : t -> t -> comparison
        val ( + ) : t -> t -> t
        val ( * ) : t -> t -> t
        val inv : t -> t
        val neg : t -> t
        val zero : t
        val one : t
      end