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!
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