lambda.xy.x
lambda.xy.x

Reputation: 4998

module alias of mli file

I have the following situation:

The mli file ds.mli contains just a type declaration:

type t = A of int | B of string

Now I would like to make an alias to Ds in another module user.ml:

module D = Ds

On compilation I get the following error message from the linker:

$ ocamlc ds.mli user.ml 
File "user.ml", line 1:
Error: Error while linking user.cmo:
Reference to undefined global `Ds'

If I copy ds.mli to ds.ml and call

 $ ocamlc ds.mli ds.ml user.ml 

The compilation goes through.

Is there a possibility to avoid creating the ds.ml file?

Remark: I am aware of the difference between implementation and interface files, but to my knowledge, as long as the interface contains only type definitions, an implementation file is not necessary. Assume we add the following module signature to ds.mli:

module T : sig
  type t = C | D
end

Then the the definition of bar in user:

let bar = function
  | Ds.T.C -> true
  | Ds.T.D -> false

compiles without problems via

$ ocamlc ds.mli user.ml

The expansion of the alias to the signature should not be the problem.

Edit: forgot to add ds.ml to the arguments of the second ocamlc call. Edit: added remark about using mli files.

Upvotes: 2

Views: 348

Answers (2)

user3240588
user3240588

Reputation: 1252

type t = A | B within a file m.ml is basically the same as module M = struct type t = A | B end. The same line in a file m.mli corresponds to module M : sig type t = A | B end The former implements a module. The latter is just a module signature.

A signature can be used to declare types but more commonly it is used to mask some parts of a module implementation to the outside world. The signature never actually implements a module, even if the module only contains type declarations.

A module is like a value, not a type. For instance, modules can be wrapped and manipulated as values in the language ('first-class modules') and can be used as arguments to functors in the module language.

The fact that the function bar works with only the .mli file present is not a contradiction to this; it is a pattern matching on types, and no values of the types are required to exist for defining the function. If you add in user something like let c = Ds.T.C then you have constructed such a value, but this has happened in user.ml, an implementation file.

Upvotes: 4

Richard-Degenne
Richard-Degenne

Reputation: 2949

The line you got it wrong is

module D = Ds

Here, you're trying to "affect" a module type to a module, and that's not gonna happen.

However, you can do the same with a module type:

module type D = module type of Ds

Upvotes: 2

Related Questions