Felix
Felix

Reputation: 8495

Can I implement multiple module types with 1 module?

Given these module types:

module type CodecTypes = {
  type t;
  type token;
};

module type Decode = {
  include CodecTypes;
  let decode: BsGenericParser.Parse.parser(token, t);
};

module type Encode = {
  include CodecTypes;
  let encode: t => list(token);
};

Is there a way to share the abstract types t and token between the two module types? I tried:

module type Codec = {
  include Encode;
  include Decode;
}

but the compiler complains about name clashes.

Upvotes: 3

Views: 63

Answers (1)

glennsl
glennsl

Reputation: 29106

Indeed you can, using signature constraints with destructive substitution:

module type Codec = {
  include Encode;
  include Decode with type t := t and type token := token;
}

Note that you can also write signature constraints with = instead of:=, but this will yield the same error. The difference between them is that = is a type equality that require the type on both sides to be equal, and := will replace ("destructively substitute") the type on the left-hand side. In this case that means Decode.t is replaced by Encode.t.

To better illustrate this, consider this example:

module type Codec = {
  type u;
  include Encode with type t := u;
  include Decode with type t := u and type token := token;
}

which will result in the following module type:

module type Codec = {
  type u;
  type token;
  let encode: u => list(token);
  let decode: list(token) => u;
};

where t no longer occurs at all, having been replaced by u instead.

Upvotes: 3

Related Questions