15

In OCaml, I have two module types defining a type t:

module type Asig = sig
    type t
    val a : t
end

module type Bsig = sig
    type t
    val b : t
end

I want to automate the creation of a module type merging them. I want to create a module type equivalent to:

module type ABsig_manual = sig
    type t
    val a : t
    val b : t
end

I tried

module type ABsig = sig
    include Asig
    include Bsig
end

but this fails with Error: Multiple definition of the type name t. It seems impossible to add a type constraint to the include so I'm stuck.

Context: I have a module AB that does implement both signatures and I want to feed it to a functor like:

module MakeC(AB) = struct
    type t = AB.t list
    let c = [AB.a; AB.b]
end

module C = MakeC(AB)

I could use two arguments like in:

module UglyMakeC(A : Asig)(B : Bsig with type t = A.t) = struct
    type t = A.t list
    let c = [A.a; B.b]
end

module C = UglyMakeC(AB)(AB)

but this (is ugly and) doesn't scale well to more functors or more signatures to merge.

So, how can I automate merging those two module types? I can modify A and B as needed but I want to keep them separated. Also, maybe my approach is completely wrong, and in that case I'd love pointers to a better direction.

Type sharing in OCaml - typechecker error is related but merges modules, not module types.

Community
  • 1
  • 1
jacquev6
  • 620
  • 4
  • 18

1 Answers1

25

Here is the way to do it :

module type Asig = sig
    type t
    val a : t
end

module type Bsig = sig
    type t
    val b : t
end

module type ABsig = sig
    include Asig
    include Bsig with type t := t
end

It's called "destructive substitution".

Drup
  • 3,679
  • 13
  • 14
  • 4
    For future reference, this is documented in "Language extensions", paragraph "Substituting inside a signature" (http://caml.inria.fr/pub/docs/manual-ocaml/extn.html#sec234), which extends what's described in "The OCaml Language", paragraph "Module types" (http://caml.inria.fr/pub/docs/manual-ocaml/modtypes.html). – jacquev6 Oct 03 '15 at 06:05
  • 1
    More durable link to reference: http://caml.inria.fr/pub/docs/manual-ocaml-4.07/extn.html#sec249 (secXXX anchors in ref manual are modified for each new version of OCaml) – jacquev6 Aug 15 '18 at 08:25
  • 3
    Real World OCaml (pp. 186-187) proposes an alternative solution to this type of situation, explaining "[t]his is somewhat cleaner when combining multiple interfaces, since it correctly reflects that all of the signatures are being handled equivalently": `module type ABsig = sig type t include Asig with type t := t include Bsig with type t := t end` – fishyfriend Jan 14 '19 at 01:43