Reputation: 49
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!
Upvotes: 2
Views: 284
Reputation: 18892
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
Upvotes: 6