Suppose I have a module A
, with the following interface and implementation files:
(* a.mli *)
module type A_SIG =
sig
val f: int -> int
...
end
(* a.ml *)
module A : A_SIG =
struct
let f x = x + 1
...
end
Compiling a.mli
followed by a.ml
fails, with error Unbound module type A_SIG
. Duplicating the entire signature in the implementation file fixes it.
Why is this the case? It seems that the following works in SML:
(* a.sig *)
signature A_SIG =
sig
val f: int -> int
...
end
(* a.sml *)
structure A : A_SIG =
struct
fun f x = x+1
...
end
I've seen this similar post, but its answer is unclear to me.
The file a.ml
is implicitly wrapped as the module A
and the file a.mli
is implicitly wrapped as the module type A
.
So the following works
(* A.mli *)
val f : int -> int
(* A.ml *)
let f x = x + 1
And you would access f
from another module as A.f
.
Or if you really want submodules you could write
(* a.mli *)
module type A_SIG =
sig
val f: int -> int
end
module A : A_SIG
(* a.ml *)
module type A_SIG =
sig
val f: int -> int
end
module A : A_SIG =
struct
let f x = x + 1
end
And you would access f
from another module as A.A.f
and the module A
would also contain the signature A_SIG
, in addition to the (sub)module A
.
Implementations of Standard ML do not normally implicitly wrap the contents of a file as a module.
For completeness, note that OCaml has a feature to "generate" a module type from a module:
(* a.mli *)
module type A_SIG =
sig
val f: int -> int
end
module A : A_SIG
(* a.ml *)
module A =
struct
let f x = x + 1
end
module type A_SIG = module type of A