Greg Nisbet
Greg Nisbet

Reputation: 6994

OCaml share structure between mli file and signature inside ml file

The thing I'm ultimately trying to do is 1) restrict visibility into a module (hence the mli file) and 2) define a functor where the argument has a "canonical implementation" that lives in the source tree as an ml/mli pair and insists that arguments have the same shape as this canonical implementation.

Suppose I have a file concat.ml that contains a single function for string concatenation

(* concat.ml *)
type t = string
let concat x y = x ^ y

and I have an interface for it

(* concat.mli *)
type t
val concat : t -> t -> t

However, I also have a functor join that looks like this and expects something with the same shape as Concat. (The implementation of join is intentionally naive):

(* join.ml *)
module Join(X : Concat_type.TYPE) : sig
  val join : X.t list -> X.t
end = struct
  let rec join xs = match xs with
    | [] -> failwith "can't be empty"
    | [x] -> x
    | [x; y] -> X.concat x y
    | (x::xs') -> X.concat x (join xs')
end

In order to express the "same shape as Concat" constraint, I've had to make another ml file concat_type.ml that looks like this:

(* concat_type.ml *)
module type TYPE = sig
  type t
  val concat : t -> t -> t
end

Concat_type.TYPE and the Concat mli are nearly identical in this case. The only reason I made concat_type.ml at all was to support the functor Join and explicitly restrict what it can see if I try to apply it to a module mimicking the implementation of concat.

Is there a way to import Concat_type.TYPE into the Concat interface or vice versa or some other way to avoid duplication between them?

Upvotes: 3

Views: 511

Answers (1)

ivg
ivg

Reputation: 35210

Yes, it is possible to express the Concat module interface via the Concat_type.TYPE module type. It is also possible to get a module type of an existing module.

The first approach looks like this:

(* concat.mli *)
include Concat_type.TYPE

The second approach allows you to get rid of the Concat_type, though I personally dislike it, as I don't like the module type of construct. But still, there is a possibility:

module type Concat = module type of Concat

module Join (X : Concat) = struct 
  ...
end

Upvotes: 2

Related Questions