I’ve copied your code into TryOCaml, see the link here.
If you click on the ‘Eval code’ button, you’ll see what the types are for the various modules.
In particular, you’ll see that module A has type ELT, and if you look at the definition of ELT you’ll see that it never mentions the int type. So the link between A.t and int has been hidden. As @orbitz noted, this is because module A : ELT in the definition explicitly tells the compiler to forget the actual type and use the abstract ELT type instead. If you remove the : ELT annotation you’ll get the link between the types back.
The same happens again for the link between Test.t and int list. If you look at your functor MakeL, here is the type printed in the toplevel:
module MakeL :
functor (E : ELT) ->
sig
type elt = E.t
type t
val vide : t
val element_de : elt -> t -> bool
val ajout : t -> elt -> t
end
You can see that it never mentions any lists, so even after fixing the issue with A you’ll get the same error about the type of l1.
Here you have two solutions: either you choose to expose the details of your implementation, to allow the rest of the code to use lists and sets equivalently, or you keep the details hidden and use the functions from your module to create the sets.
Concretely, the first option means adding an extra constraint on the return type of your functor: module MakeL(E : ELT) : S with type elt = E.t and type t = E.t list = ...
The second option means updating the definition of l1: let l1 = Test.ajout (Test.ajout (Test.ajout Test.vide 1) 4) 5
The second option is more idiomatic, but the first option makes it easier to see the values in the toplevel, so it might be interesting for you to experiment with both ideas.
Also, on an unrelated subject, please note that let compare x y = x - y is dangerous, as it will return wrong results in case of overflow (for instance, compare max_int (-1) will return a negative number, implying that max_int is smaller than -1).