Further refining the signature of a nested module

2019-07-10 04:57发布

问题:

I have an ML file which contains a nested module. For example:

let f n = n + 1

module type M_type = sig
  val g : int -> int
  val h : int -> int
end

module M : M_type = struct
  let g n = n + 2
  let h n = n + 3
end

let j n = n |> M.h |> M.g |> f

When writing an MLI for this ML, I wish not to expose M.h, but I do wish to expose M.g.

Such as the following:

module type M_type = sig
  val g : int -> int
end

module M : M_type

val j : int -> int

The above combination of ML and MLI does not compile.

The idea is that my nested module M contains some functions that I do wish to expose to other functions in the parent module, but not to a user of the parent module.

Is there a legal way to achieve this? If there is none, what is the best alternative to achieve this kind of narrowing of the signature?

Thanks!

回答1:

If you look closely at the compiler error:

 Module type declarations do not match:
         module type M_type = sig val g : int -> int val h : int -> int end
       does not match
         module type M_type = sig val g : int -> int end

you will see that the compiler does not complain about the module M, but about the module type M_type.

Indeed, the definition of the two module type does not match:

module type M_type = sig
  val g : int -> int
  val h : int -> int
end

is not compatible with

module type M_type = sig
  val g : int -> int
end

There are many ways to fix this problem. One possibility is to not use module type as signature constraint when unneccessary:

(* a.ml *)
module M = struct
  let g n = n + 2
  let h n = n + 3
end

Similarly, the mli file can be written as

(*a.mli*)    
module M : sig val g: int -> int end

Another possibility is to only define the constrained module type

(* a.ml *)
module type M_type = sig val g: int -> int end
module M: sig include M_type val h: int -> int end =
(* Note that the signature constraint above is not necessary *)
struct
  let g n = n + 2
  let h n = n + 3
end

with the associated mli file:

(*a.mli*)
module type M_type = sig val h: int -> int end    
module M : sig val g: int -> int end

It is also possible to define an extended module type EXT for the .ml file:

module type M_type = sig val g: int -> int end
module type EXT = sig include M_type val h: int -> int end
module M: EXT = struct
  let g n = n + 2
  let h n = n + 3
end


标签: ocaml