I want to create a library (for instance test.cma
) of a small project that consists of several files: types.ml
, parse.ml
, and utils.ml
. I would like the namespace to be flat: I want to have access to the types and functions of all three files directly under Test
(i.e,. Test.parse : string -> ast
and not Test.Parse.parse : string -> Types.ast
). Is it possible to create such a library, or do I need to write a master file that collects everything?
You can write a test.ml
file as follows:
include Types
include Utils
include Parse
Best wishes,
Nicolás
Thank you for the suggestion. It seems like the simplest solution indeed.
I have a followup question: how can I do the same thing in the mli? I tried include
but it does not seem to work (I have types.cmi, but if I do include Types
I get an error).
You need to use include module type of Types
.
Best wishes,
Nicolás
Thanks a lot, that works great.
So our solution was something like this (we decided to put Utils
as a submodule):
mylib.mli
:
include module type of Types
module Utils : sig
include module type of Utils
end
mylib.ml
:
include Types
module Utils = struct
include Utils
end
compiled as
ocamlc -c *.ml
ocamlc -a -o mylib.cma types.cmo utils.cmo mylib.cmo
I wonder if there is a simpler solution (I tried using pack
but I cannot achieve the same result). And if there are pointers to workflows to create libraries in OCaml, I’d love to read them.
Thanks again!
Looks OK to me. You can shorten your file by writing module Utils = Utils
in both the implementation and the interface.
Best wishes,
Nicolás
It is worth noticing that module Utils = Utils
is not only shorter but gives more informations to the type checker (for instance, if F
is an applicative functor introducing an abstract type t
, F(Utils).t
and F(Types.Utils).t
will be equal if Utils
and Types.Utils
are known to be aliases).
Anyway, you may shorten your code:
into that (which is, as far as I know, strictly equivalent):
module Utils : module type of Utils
and these two forms are weaker than:
module Utils : module type of struct include Utils end
(weaker in the sense that if Utils
introduces an abstract type t
, the two types are unrelated in the first version, whereas they are equal in the second one), and this form is in turn weaker than
module Utils = Utils
where we get equalities between abstract types under functor application, as I mentioned in the beginning.
Wouldn’t it be simpler in this case to just remove test.mli
?
This was enlightening, thanks a lot!
We don’t want to expose everything from the submodule, so we prefer to have a mli.