Friend Modules in OCaml - module

I currently have two "layers" of modules that represent identifier-data relationships in a database.
The first layer defines identifier types, such as IdUser.t or IdPost.t while the second layer defines data types such as User.t or Post.t. I need all the modules of the first layer to be compiled before the modules of the second layer, because a Post.t must hold the IdUser.t of its author and the User.t holds the IdPost.t of the last five posts he visited.
Right now, IdUser.t provides functionality that should only ever be used by User.t, such as the ability to transform an IdUser.t into an IdUser.current: for security reasons, this transform must only ever be performed by the function User.check_password. Since IdUser and User are independent modules, I need to define those features as public functions and rely on conventions to avoid calling them anywhere outside of User, which is rather dirty. A symmetrical situation happens in IdPost.mine:
module IdUser : sig
type t
type current
val current_of_t : t -> current (* <--- Should not be public! *)
end = struct
type t = string
type current = string
let current_of_t x = x
end
module IdPost : sig
type t
type mine
val mine_of_t : t -> mine (* <--- Should not be public! *)
end = struct
type t = string
type mine = string
let mine_of_t x = x
end
module Post : sig
(* Should not "see" IdUser.current_of_t but needs IdPost.mine_of_t *)
val is_mine : IdUser.current -> IdPost.t -> IdPost.mine
end
module User : sig
(* Should not "see" IdPost.mine_of_t but needs IdUser.current_of_t *)
val check_password : IdUser.t -> password:string -> IdUser.current
end
Is there a way of defining an current_of_t : t -> current function in IdUser that can only be called from within module User ?
EDIT: this was a simplified example of one pair of modules, but there's an obvious solution for a single pair that cannot be generalized to multiple pairs and I need to solve this for multiple pairs — about 18 pairs, actually... So, I've extended it to be an example of two pairs.

So IdUser is in reality an existential type: For User there exists a type
IdUser.current such that the public IdUser.t can be lifted to it. There are a couple of ways to encode this: either functorize User as Gasche shows if statically managing the dependence is sufficient, or use first-class modules or objects if you need more dynamism.
I'll work out Gasche's example a bit more, using private type abbreviations for convenience and to show how to leverage translucency to avoid privatizing implementation types too much. First, and this might be a limitation, I want to declare an ADT of persistent IDs:
(* File id.ml *)
module type ID = sig
type t
type current = private t
end
module type PERSISTENT_ID = sig
include ID
val persist : t -> current
end
With this I can define the type of Posts using concrete types for the IDs but with ADTs to enforce the business rules relating to persistence:
(* File post.ml *)
module Post
(UID : ID with type t = string)
(PID : PERSISTENT_ID with type t = int)
: sig
val is_mine : UID.current -> PID.t -> PID.current
end = struct
let is_mine uid pid =
if (uid : UID.current :> UID.t) = "me" && pid = 0
then PID.persist pid
else failwith "is_mine"
end
The same thing with Users:
(* File user.ml *)
module User
(UID : PERSISTENT_ID with type t = string)
: sig
val check_password : UID.t -> password:string -> UID.current
end = struct
let check_password uid ~password =
if uid = "scott" && password = "tiger"
then UID.persist uid
else failwith "check_password"
end
Note that in both cases I make use of the concrete but private ID types. Tying all together is a simple matter of actually defining the ID ADTs with their persistence rules:
module IdUser = struct
type t = string
type current = string
let persist x = x
end
module IdPost = struct
type t = int
type current = int
let persist x = x
end
module MyUser = User (IdUser)
module MyPost = Post (IdUser) (IdPost)
At this point and to fully decouple the dependencies you will probably need signatures for USER and POST that can be exported from this module, but it's a simple matter of adding them in.

One way that seems to work at least on your simplified example is to group IdUser and User inside a same module:
module UserAndFriends : sig ... end = struct
module IdUser : sig
...
end = struct
...
end
module User = struct
...
end
end
module Post : sig
val create : (* <--- Should not "see" IdUser.current_of_t *)
author:IdUser.current -> title:string -> body:string -> IdPost.t
end
Hiding the dangerous function(s) in the signature of UserAndFriends gives the result you desire. If you do not want to make a big file containing both IdUser and User, you can use option -pack of ocamlc to create UserAndFriends. Note that in this case, you must craft your Makefile carefully so that the .cmi files of IdUser and User are not visible when compiling Post. I am not the Makefile specialist for Frama-C, but I think we use separate directories and position the compiler option -I carefully.

I suggest you parametrize Post (and possibly User for consistency) by a signature for the IdUser module : you would use a signature with current_of_t for User, and one without for Post.
This guarantee that Post doesn't use IdUser private features, but the public interface of IdUser is still too permissive. But with this setup, you have reversed the dependencies, and IdUser (the sensitive part) can control its use directly, give itself (with the private part) to IdUser and restrict the public signature to the public parts.
module type PrivateIdUser = sig
val secret : unit
end
module type PublicIdUser = sig
end
module type UserSig = sig
(* ... *)
end
module MakeUser (IdUser : PrivateIdUser) : UserSig = struct
(* ... *)
end
module IdUser : sig
include PublicIdUser
module User : UserSig
end
= struct
module IdUser = struct
let secret = ()
end
module User = MakeUser(IdUser)
include IdUser
end
module Post = struct
(* ... *)
end
Edit : Pascal Cuoq's concurrent -- in the temporal sense -- solution is alos very nice. Actually it's simpler and has less boilerplate. My solution adds an abstraction that allows for slightly more modularity, as you can define User independently of IdUser.
I think which solution is best probably depends on the specific application. If you have a lot of different modules that use PrivateIdUser private information, then using functors to write them separately instead of bundling everyone in the same module can be a good idea. If only User needs to be in the "private zone" and it's not very big, then Pascal's solution is a better choice.
Finally, while being forced to explicit Private and Public interfaces can be seen as an additional burden, it is also a way to make the access properties of different modules more explicit that using the position inside the module hierarchy.

It's possible to achieve fine-grained control over signatures with a combination of recursive modules, first-class modules and GADTs, but the limitation would be that all modules should then be inside the same top-level module and unpackings of first-class modules inside the recursive modules should be done in each function separately (not on the module-level as it would cause runtime exception Undefined_recursive_module):
module rec M1 : sig
module type M2's_sig = sig
val a : int
val c : float
end
module type M3's_sig = sig
val b : string
val c : float
end
type _ accessor =
| I'm_M2 : M2.wit -> (module M2's_sig) accessor
| I'm_M3 : M3.wit -> (module M3's_sig) accessor
val access : 'a accessor -> 'a
type wit
val do_it : unit -> unit
end = struct
module type M2's_sig = sig
val a : int
val c : float
end
module type M3's_sig = sig
val b : string
val c : float
end
type _ accessor =
| I'm_M2 : M2.wit -> (module M2's_sig) accessor
| I'm_M3 : M3.wit -> (module M3's_sig) accessor
module M1 = struct
let a = 1
let b = "1"
let c = 1.
end
let access : type a. a accessor -> a =
function
| I'm_M2 _ -> (module M1)
| I'm_M3 _ -> (module M1)
type wit = W
let do_it () =
let (module M2) = M2.(access ## I'm_M1 W) in
let (module M3) = M3.(access ## I'm_M1 W) in
Printf.printf "M1: M2: %d %s M3: %d %s\n" M2.a M2.b M3.a M3.b
end
and M2 : sig
module type M1's_sig = sig
val a : int
val b : string
end
module type M3's_sig = sig
val b : string
val c : float
end
type _ accessor =
| I'm_M1 : M1.wit -> (module M1's_sig) accessor
| I'm_M3 : M3.wit -> (module M3's_sig) accessor
val access : 'a accessor -> 'a
type wit
val do_it : unit -> unit
end = struct
module type M1's_sig = sig
val a : int
val b : string
end
module type M3's_sig = sig
val b : string
val c : float
end
type _ accessor =
| I'm_M1 : M1.wit -> (module M1's_sig) accessor
| I'm_M3 : M3.wit -> (module M3's_sig) accessor
module M2 = struct
let a = 2
let b = "2"
let c = 2.
end
let access : type a. a accessor -> a =
function
| I'm_M1 _ -> (module M2)
| I'm_M3 _ -> (module M2)
type wit = W
let do_it () =
let (module M1) = M1.(access ## I'm_M2 W) in
let (module M3) = M3.(access ## I'm_M2 W) in
Printf.printf "M2: M1: %d %f M3: %d %f\n" M1.a M1.c M3.a M3.c
end
and M3 : sig
module type M1's_sig = sig
val a : int
val b : string
end
module type M2's_sig = sig
val a : int
val c : float
end
type _ accessor =
| I'm_M1 : M1.wit -> (module M1's_sig) accessor
| I'm_M2 : M2.wit -> (module M2's_sig) accessor
val access : 'a accessor -> 'a
type wit
val do_it : unit -> unit
end = struct
module type M1's_sig = sig
val a : int
val b : string
end
module type M2's_sig = sig
val a : int
val c : float
end
type _ accessor =
| I'm_M1 : M1.wit -> (module M1's_sig) accessor
| I'm_M2 : M2.wit -> (module M2's_sig) accessor
module M3 = struct
let a = 3
let b = "3"
let c = 3.
end
let access : type a. a accessor -> a =
function
| I'm_M1 _ -> (module M3)
| I'm_M2 _ -> (module M3)
type wit = W
let do_it () =
let (module M1) = M1.(access ## I'm_M3 W) in
let (module M2) = M2.(access ## I'm_M3 W) in
Printf.printf "M3: M1: %s %f M2: %s %f\n" M1.b M1.c M2.b M2.c
end
let () =
M1.do_it ();
M2.do_it ();
M3.do_it ()

Related

How to create a set of elements without knowing the type of the element?

I'm running into problems around recursive/mutually referential module definitions trying to use Caml's Map/Set stuff. I really want ones that just work on types, not modules. I feel like it should be possible to do this with first-class modules, but I'm failing to make the syntax work.
The signature I want is:
module type NonFunctorSet = sig
type 'a t
val create : ('a -> 'a -> int) -> 'a t
val add : 'a t -> 'a -> 'a t
val remove : 'a t -> 'a -> 'a t
val elements : 'a t -> 'a list
end
Possibly with other Caml.Set functions included. My idea for how this would work is something like:
type 'a t = {
m : (module Caml.Set.S with type elt = 'a);
set : m.t
}
let create (compare : 'a -> 'a -> t) =
module m = Caml.Set.Make(struct type t = 'a let compare = compare end) in
let set = m.empty in
{m = m; set = set;}
end
But that doesn't work for a number of reasons; 'a isn't exposed in the right places, I can't reference m.t in the same record where m was defined, etc.
Is there a version of this that works?
Adding more context about my use case:
I have two modules, Region and Tribe. Tribe needs access to a lot of the interface of Region, so I am currently creating Tribe as a functor, MakeTribe(Region : RegionT). Region mostly doesn't need to know about Tribe, but it does need to be able to store a mutable collection of Tribe.t that represent the tribes living in that region.
So, somehow or other, I need a RegionT like
module type RegionT = sig
type <region>
val get_local_tribes : <region> -> <tribes>
val add_tribe : <region> -> <tribe> -> unit
...
end
I don't really care about the specific syntax of <tribe>, <tribes> and <region> in this, so long as the fully built Tribe module can know that Region.get_local_tribes, etc, will yield an actual Tribe.t
The circular dependency problem is that the type <tribe> does not exist until the module Tribe is created. My idea so far has been to have RegionT.t actually be 'a RegionT.t, and then Tribe could simply refer to Tribe.t Region.t. This is all fine if I'm satisfied with keeping a <tribe> list inside Region, but I want it to be a set.
I feel this should be possible based on the following example code :
module Example : sig
type t
val compare : t -> t -> int
end = struct
type t = int
let compare = Int.compare
end
module ExampleSet = Caml.Set.Make(struct type t = Example.t let compare = Example.compare end)
All that Example exposes in its interface is a type and a function from two instances of that type to an int; why is that more than having a 'a -> 'a -> int, which has the same things?
Using Polymoprhic Sets and Maps from the Base Library
In Base and Core libraries, from Jane Street, ordered data structures, such as maps, sets, hash tables, and hash sets, are all implemented as polymorphic data structures, instead of functorized versions as in the vanilla OCaml standard library.
You can read about them more in the Real World OCaml Maps and Hashtbales chapter. But here are quick recipes. When you see a comparator in the function interface, e.g., in Map.empty what it actually wants you is to give you a module that implements the comparator interface. The good news is that most of the modules in Base/Core are implementing it, so you don't have to worry or know anything about this to use it, e.g.,
# open Base;;
# let empty = Map.empty (module Int);;
val empty : (Base.Int.t, 'a, Base.Int.comparator_witness) Base.Map.t =
<abstr>
# Map.add empty 1 "one";;
- : (Base.Int.t, string, Base.Int.comparator_witness) Base.Map.t
Base.Map.Or_duplicate.t
= `Ok <abstr>
So the simple rule, if you want a set,map,hashtable,hashset where the key element has type foo, just pass (module Foo) as a comparator.
Now, what if you want to make a mapping from your custom type? E.g., a pair of ints that you would like to compare in lexicographical order.
First of all, we need to define sexp_of and compare functions. For our type. We will use ppx derivers for it, but it is easy to make it manually if you need.
module Pair = struct
type t = int * int [##deriving compare, sexp_of]
end
Now, to create a comparator, we just need to use the Base.Comparator.Make functor, e.g.,
module Lexicographical_order = struct
include Pair
include Base.Comparator.Make(Pair)
end
So now we can do,
# let empty = Set.empty (module Lexicographical_order);;
val empty :
(Lexicographical_order.t, Lexicographical_order.comparator_witness)
Base.Set.t = <abstr>
# Set.add empty (1,2);;
- : (Lexicographical_order.t, Lexicographical_order.comparator_witness)
Base.Set.t
= <abstr>
Despite that Base's data structures are polymorphic they strictly require that the module that provides the comparator is instantiated and known. You can just use the compare function to create a polymorphic data structure because Base will instantiate a witness type for each defined compare function and capture it in the data structure type to enable binary methods. Anyway, it is a complex issue, read on for easier (and harder) solutions.
Instantiating Sets on mutually dependent modules
In fact, OCaml supports mutually recursive funtors and although I would suggest you to break the recursion by introducing a common abstraction on which both Region and Tribe depend, you can still encode your problem in OCaml, e.g.,
module rec Tribe : sig
type t
val create : string -> t
val compare : t -> t -> int
val regions : t -> Region.t list
end = struct
type t = string * Region.t list
let create name = name,[]
let compare (x,_) (y,_) = String.compare x y
let regions (_,r) = r
end
and Region : sig
type t
val empty : t
val add_tribe : Tribe.t -> t -> t
val tribes : t -> Tribe.t list
end = struct
module Tribes = Set.Make(Tribe)
type t = Tribes.t
let empty = Tribes.empty
let add_tribe = Tribes.add
let tribes = Tribes.elements
end
Breaking the Dependency Loop
A much better solution would be to redesign your modules and break the dependency loop. The simplest approach would be just to choose some identifier that will be used to compare tribes, e.g., by their unique names,
module Region : sig
type 'a t
val empty : 'a t
val add_tribe : string -> 'a -> 'a t -> 'a t
val tribes : 'a t -> 'a list
end = struct
module Tribes = Map.Make(String)
type 'a t = 'a Tribes.t
let empty = Tribes.empty
let add_tribe = Tribes.add
let tribes r = Tribes.bindings r |> List.map snd
end
module Tribe : sig
type t
val create : string -> t
val name : t -> string
val regions : t -> t Region.t list
val conquer : t Region.t -> t -> t Region.t
end = struct
type t = Tribe of string * t Region.t list
let create name = Tribe (name,[])
let name (Tribe (name,_)) = name
let regions (Tribe (_,r)) = r
let conquer region tribe =
Region.add_tribe (name tribe) tribe region
end
There are also tons of other options and in general, when you have mutual dependencies it is actually an indicator of a problem in your design. So, I would still revisit the design stage and eschew the circular dependencies.
Creating Polymorphic Sets using the Vanilla OCaml Standard Library
It is not an easy task, especially if you need to handle operations that involve several sets, e.g., Set.union. The problem is that Set.Make is generating a new type for the set per each compare function so when we need to union two sets it is hard for us to prove to the OCaml compiler that they were created from the same type. It is possible but really painful, I am showing how to do this only to discourage you from doing this (and to showcase OCaml's dynamic typing capabilities).
First of all we need a witness type that will reify an OCaml type for the set into a concrete value.
type _ witness = ..
module type Witness = sig
type t
type _ witness += Id : t witness
end
Now we can define our polymorphic set as an existential that holds the set itself and the module with operations. It also holds the tid (for type identifier) that we will later use to recover the type 's of the set.
type 'a set = Set : {
set : 's;
ops : (module Set.S with type elt = 'a and type t = 's);
tid : (module Witness with type t = 's);
} -> 'a set
Now we can write the create function that will take the compare function and turn it into a set,
let create : type a s. (a -> a -> int) -> a set =
fun compare ->
let module S = Set.Make(struct
type t = a
let compare = compare
end) in
let module W = struct
type t = S.t
type _ witness += Id : t witness
end in
Set {
set = S.empty;
ops = (module S);
tid = (module W);
}
The caveat here is that each call to create will generate a new instance of the set type 's so we can compare/union/etc two sets that were created with the same create function. In other words, all sets in our implementation shall share the same ancestor. But before that lets take a pain and implement at least two operations, add and union,
let add : type a. a -> a set -> a set =
fun elt (Set {set; tid; ops=(module Set)}) -> Set {
set = Set.add elt set;
ops = (module Set);
tid;
}
let union : type a. a set -> a set -> a set =
fun (Set {set=s1; tid=(module W1); ops=(module Set)})
(Set {set=s2; tid=(module W2)}) ->
match W1.Id with
| W2.Id -> Set {
set = Set.union s1 s2;
tid = (module W1);
ops = (module Set);
}
| _ -> failwith "sets are potentially using different types"
Now, we can play with it a bit,
# let empty = create compare;;
val empty : '_weak1 set = Set {set = <poly>; ops = <module>; tid = <module>}
# let x1 = add 1 empty;;
val x1 : int set = Set {set = <poly>; ops = <module>; tid = <module>}
# let x2 = add 2 empty;;
val x2 : int set = Set {set = <poly>; ops = <module>; tid = <module>}
# let x3 = union x1 x2;;
val x3 : int set = Set {set = <poly>; ops = <module>; tid = <module>}
# let x4 = create compare;;
val x4 : '_weak2 set = Set {set = <poly>; ops = <module>; tid = <module>}
# union x3 x4;;
Exception: Failure "sets are potentially using different types".
#

Abstract types in modules in OCaml

I have very simple signature and module in OCaml:
module type S = sig
type t
val y : t
end;;
and
module M2 : S = struct
type t = int
let x = 1
let y = x+2
end;;
I cannot use construction like
M2.y
to get 3 unless i specify the module as
module M2 : S with type t = int = struct ...
Why is it so? There already is statement, that type t = int
The concrete, int value for M2.y is indeed not available because the following two conditions are met:
the type of y is abstract in the signature S
(there is no type t = ... there)
the module M2 is made opaque with respect to the signature S
(in other words, it is restricted to the signature S via the notation : S)
As a result, you indeed obtain:
let test = M2.y ;;
(* val test : M2.t = <abstr> *)
As suggested by the keyword <abstr>, this is related to the notion of abstract type. This notion is a very strong feature enforced by OCaml's typing rules, which prevents any user of a module having signature S to inspect the concrete content of one such abstract type. As a result, this property is very useful to implement so-called abstract data types (ADT) in OCaml, by carefully separating the implementation and the signature of the ADT.
If any of the two conditions above is missing, the type won't be abstract anymore and the concrete value of y will show up.
More precisely:
If the type t is made concrete, you obtain:
module type S = sig
type t = int
val y : t
end
module M2 : S = struct
type t = int
let x = 1
let y = x+2
end
let test = M2.y ;;
(* val test : M2.t = 3 *)
But in practice this is not very interesting because you lose generality. However, a somewhat more interesting approach consists in adding an "evaluator" or a "pretty-printer" function to the signature, such as the value int_of_t below:
module type S = sig
type t
val y : t
val int_of_t : t -> int
end
module M2 : S = struct
type t = int
let x = 1
let y = x+2
let int_of_t x = x
end
let test = M2.(int_of_t y) ;;
(* val test : int = 3 *)
Otherwise, if the module M2 is made transparent, you obtain:
module type S = sig
type t
val y : t
end
module M2 (* :S *) = struct
type t = int
let x = 1
let y = x+2
end
let test = M2.y ;;
(* val test : int = 3 *)
Finally, it may be helpful to note that beyond that feature of abstract types, OCaml also provides a feature of private types that can be viewed as a trade-off between concrete and abstract types used in a modular development. For more details on this notion, see for example Chap. 8 of Caml ref man.

expose a private type for module extension in OCaml

I'd like to extend a module but I need access to its private components. Here's an example:
nat.mli:
type t
val zero : t
val succ : t -> t
nat.ml:
type t = int
let zero = 0
let succ x = x + 1
I'd like to define a new module Ext_nat that defines a double function. I was trying to do something like this.
ext_nat.mli:
include (module type of Nat)
val double : t -> t
ext_nat.ml:
include Nat
let double x = 2 * x
It's not working as I don't have access to the representation of x in the last line.
Now that I'm thinking about this, it may not be such a good idea anyway because this would break the encapsulation of nat. So what is the best way to do this? I could define a new module nat_public where type t = int in the signature, and define nat and ext_nat with a private type t. What do you think?
You need to use with type statement. It is possible to write the code below in many different ways, but the idea is always the same.
module type NatSig =
sig
type t
val zero : t
val succ : t -> t
end
module type ExtNatSig =
sig
include NatSig
val double : t -> t
end
module ExtNat : ExtNatSig =
struct
type t = int
let zero = 0
let succ = fun x -> x + 1
let double = fun x -> x * 2
end
module Nat = (ExtNat : NatSig with type t = ExtNat.t)
let z = Nat.zero
let _ = ExtNat.double z
The problem is that as far as I remember it's impossible to achieve this behavior with your file structure: you define your module implicitly with signature in .mli file and structure itself in .ml, so you don't have enough control over you module, that's why I suggest you to reorganize your code a little bit (if it's not a problem).

Return different first class modules in OCaml

I want to return different modules from a function. This is the general idea of what I wish would work.
module type First = sig
val speak : unit -> unit
end
module First = struct
let speak () = print_endline "hi"
end
module type Second = sig
val another_speaker : unit -> unit
end
module Second = struct
let another_speaker () = print_endline "another hi"
end
type mods = First | Second
let load = function
| First -> (module First : First)
| Second -> (module Second : Second)
1) But it doesn't because load's return type gets determined on the first match. How can I make this general idea work?
2) How can I write something like this and have it work.
type a = [`First of (module type First )]
The "good" solution is to use the same module type for everyone:
module type S = sig
val speak : unit -> unit
end
module First = struct
let speak () = print_endline "hi"
end
module Second = struct
let speak () = print_endline "another hi"
end
type mods = First | Second
let load = function
| First -> (module First : S)
| Second -> (module Second : S)
If you really can't, apart from the variant solution given by Jeffrey, there is the GADT solution:
type 'a t = First : (module First) t | Second : (module Second) t
let load : type a . a t -> a = function
| First -> (module First : First)
| Second -> (module Second : Second)
You can't treat the two module types as the same type, because they're different. But you can combine them into a variant type.
This works for me:
module type First = sig
val speak : unit -> unit
end
module type Second = sig
val another_speaker : unit -> unit
end
type modvar = MFirst of (module First) | MSecond of (module Second)
type mods = First | Second
module First = struct
let speak () = print_endline "hi"
end
module Second = struct
let another_speaker () = print_endline "another hi"
end
let load = function
| First -> MFirst (module First)
| Second -> MSecond (module Second)
I'm not sure if this is what you're looking for.
Update
Here's the same code rewritten to use polymorphic variants:
module type First = sig
val speak : unit -> unit
end
module type Second = sig
val another_speaker : unit -> unit
end
type mods = First | Second
module First = struct
let speak () = print_endline "hi"
end
module Second = struct
let another_speaker () = print_endline "another hi"
end
let load = function
| First -> `MFirst (module First: First)
| Second ->`MSecond (module Second: Second)
The key is that you need to tag the values returned by load. Otherwise they have to be the same type, which they aren't.

Relaxing type checking when using 'with type' construction in modules

I have defined two module types and two modules
module type FOO = sig type e end
module type BAR = sig type t end
module Foo : FOO = struct type e = int end
module Bar : BAR = struct type t = int end
Then I define a functor as
module Fun (F:FOO) (B:BAR with type t = F.e) = struct type x = string end
(this is a toy example, please ignore the fact that F and B are not used by the functor)
Now, if I define the module
module Bla = Fun (Foo) (Bar)
I get
Error: Signature mismatch:
Modules do not match:
sig type t = Bar.t end
is not included in
sig type t = Foo.e end
Type declarations do not match:
type t = Bar.t
is not included in
type t = Foo.e
Although both Bar.t and Foo.e are defined as int OCaml considers Bar.t and Foo.e to be different. That's just the way the typing system works and it makes sense to consider these two types different in general (c.f. last paragraph of Functors and Type Abstraction).
Question: Sometimes I may want this to pass type checking because for my purposes they can be considered equal. Is there a way to relax this?
Using gasche's suggestion of removing coercion, the above code can be written as
module type FOO = sig type e end
module type BAR = sig type t end
module Foo = struct type e = int end
module Bar = struct type t = int end
module Fun (F : FOO with type e=int) (B : BAR with type t = int) = struct type x = F.e * B.t end
module Bla = Fun (Foo) (Bar)
which compiles fine. Strangely, I get
# let f x : Bla.x = (x,x);;
val f : Foo.e -> Bla.x = <fun>
Question: why does it infer that x is Foo.e? It could as well be Bar.t?
The problem is how you define Foo and Bar : module Foo : FOO = .... By imposing this signature here, you "seal" the module and make the type abstract. It cannot be reverted. You should remove the : FOO coercion here, and use it later when you need the abstraction. You could also use module Foo : (FOO with type e = int) = ....
I'm not sure how the printer chooses amongst equal types, but in this case you can cause it to print a different name by explicitly annotating your function argument:
# let f (x:Bar.t) : Bla.x = (x,x);;
val f : Bar.t -> Bla.x = <fun>