Since the module exports a function which returns an IdMap, I need to declare IdMap in the signature of the module. I think this is what was discussed in 8546, which seemed to suggest:
module IdMap : module type of Map.Make(Int)
My question is: is this correct, and could you point me to the section of the manual that explains this? (I am assuming it’s common to want to declare the outputs of functors in a signature; but if it’s idiomatic to do something else I would be very happy to know that also.)
Your module declaration is correct in isolation, but it’s hard for me to tell if this is what you want to do without more information. Here is an alternative :
module IdMap : Map.S with type key = int (* or type key := int if you want a destructive replacement *)
I tend to use this one but I have to admit I could not explain why.
By the way, by returning an IdMap do you mean returning a first class module of the same type as Map.Make(Int) ? In this case you probably want to declare a module type instead of a module :
module type IDMAP = Map.S with type key = int
val build_map: foo -> (module IDMAP)
Ah, sorry: I was unclear. I meant “returning a value whose type is 'a IntMap.t”. (I think that’s how one writes it, anyway. I’m certainly returning a map from ints to things.)
I don’t know what destructive replacement is (which I think tells you what my level is!), however I can look up your alternative in the docs, I suspect, and read what it means. I think this will help me!
I use it because module type of introduces an extra indirection for someone looking up the type of your functor, which can make documentation browsing tiresome; I try to have an explicit module type for all functor results, and glue things using with constraints. It is kind of verbose but it feels more readable to me.
With the Map.S with type key = int version, you hide the fact that 'a IdMap.t = 'a Map.Make(Int).t. This may or may not be desirable. So for example:
module M_impl = struct
module IdMap = Map.Make (Int)
module M : sig
module IdMap : Map.S with type key = int
module M' : sig
module IdMap : module type of Map.Make (Int)
module Other_map = Map.Make (Int)
(* let l = [ M.IdMap.empty; Other_map.empty ]
Error: This expression has type 'a Other_map.t
but an expression was expected of type 'b M.IdMap.t
let l = [ M.IdMap.empty; Other_map.empty ]
(* This works fine: *)
let l2 = [ M'.IdMap.empty; Other_map.empty ]
If you just want to expose particular IdMap.t values (or functions returning or consuming those values, etc.) from your module, you don’t have to expose the IdMap module: it’s perfectly legal to write they type 'a Map.Make(Int).t, as in val id_map : string list -> string Map.Make(Int).t.