Monomorphic map type

When I type module MapFromInt = Map.Make(Int) I get a module containing a map type along with functions that operate on it. This map uses int as a key, but is polymorphic in the type of the value. How can I create a module containing a map with a fixed non-polymorphic type?

The only way I know of, to create a monomorphic map from, for example, an int to a string, is to do something like this:

module MapFromIntToString = struct
  module MapFromInt = Map.Make(Int)
  type key = int
  type value = string
  type t = string MapFromInt.t
  let empty : t = MapFromInt.empty
  let is_empty : (t -> bool) = MapFromInt.is_empty
  let mem : (int -> t -> bool) = MapFromInt.mem
  let add : (int -> string -> t -> t) = MapFromInt.add

Is there a less tedious way to make a monomorphic map in OCaml?

1 Like

Hi @Ksawery_Nowak.

The following is very similar to what you’ve written, but perhaps makes it clearer that no changes to the implementation are required:

module Int_string_map : sig
  type t
  type key := int
  type data := string

  val empty : t
  val mem : key -> t -> bool
  val add : key -> data -> t -> t
  (* ... *)
end = struct
  include Map.Make(Int)
  type nonrec t = string t

In short: one can get a monomorphic map by constraining the polymorphic map to a monomorphic signature (and defining the necessary monomorphic type), but that requires writing the monomorphic signature manually.

The type of Map.S isn’t quite generic enough to let us do this without re-stating the functions we want. As an aside, it is possible to generalise it to a module type that can be monomorphised in O(1) code:

module type S_general = sig
  type 'a t
  type key
  type 'a data

  val empty : 'a t
  val mem : key -> 'a t -> bool
  val add : key -> 'a data -> 'a t -> 'a t

(* A map that is polymorphic in values, equivalent to [Map.S] *)
module type S_poly = S_general with type 'a data := 'a

(* A map that has fixed key and value types *)
module type S_mono = sig
  type t
  type data
  include S_general with type 'a t := t and type 'a data := data

This can be useful when you’d like a single functor (e.g. Map.Make) to have a return type that is easily coercible into both monomorphic and polymorphic signatures.