Avoiding duplicated definitions in module implementation and interface

When you need, say, a variant type t which is defined in foo.ml file as

type t = A | B | C
...(lots of definitions)...

Then, I think you need foo.mli like

type t = A | B | C
...(lots of definitions)...

that is, you need to repeat the definition of t. If you have a lot of definition it is a pain. Do you know what strategies can be used to solve this problem?

I think this is an old complaint but I forget what is an official solution. I also do not know the recent development of the module syntax so maybe there is a new solution for this? I checked the definition of the module syntax in the manual but can’t find anything related.

3 Likes

One approach is https://blog.janestreet.com/simple-top-down-development-in-ocaml/

Additionally, if you use dune, the next version (or v1.0?) supports using .mli only modules with some caveats, i.e. .mli file can only contain type definitions.

Dune mli/rei only modules.

3 Likes

A hackish way would be to use a preprocessor (like Martin Jambon’s cppo).
You could write once your types in a .mli file, then you #include that file where you need it.

I also very much dislike the duplication of code due to .mli files.

You can put the public types in their own .ml which also acts as the interface, without duplication.

types.ml:

type t = A | B | C

Then if you’d like to export the type from the module Foo, use include

foo.mli:

include module type of Types
...

foo.ml

include Types
...
3 Likes

Thank you. @BikalGurung’s suggestion is also in the same line.

I’m aware of this approach, but it slightly complicates the module and file structures. People expect the mli file as a documentation of the ml file, so putting important definitions to other module may confuse people.

Since it’s very simple thing, some syntactic sugar for this problem may be worth to have.

2 Likes