Module Core_kernel.Map

Map is a functional data structure (balanced binary tree) implementing finite maps over a totally-ordered domain, called a "key".

For example:

      let empty = Map.empty (module String)
      let numbers =
        Map.of_alist_exn (module String)
          ["three", Substr "three"; "four", Substr "four"]

Note that the functions in Map are polymorphic over the type of the key and of the data; you just need to pass in the first-class module for the key type (here, String).

Suppose you wanted to define a new module Foo to use in a map. You would write:

      module Foo = struct
        module T = struct
          type t = int * int
          let compare x y = Tuple2.compare Int.compare Int.compare
          let sexp_of_t = Tuple2.sexp_of_t Int.sexp_of_t Int.sexp_of_t
        end
        include T
        include Comparable.Make(T)
      end

This gives you a module Foo with the appropriate comparator in it, and then this:

      let m = Map.empty (module Foo)

lets you create a map keyed by Foo. The reason you need to write a sexp-converter and a comparison function for this to work is that maps both need comparison and the ability to serialize the key for generating useful errors. It's yet nicer to do this with the appropriate PPXs:

      module Foo = struct
        module T =
        struct  type t = int * int [@@deriving sexp_of, compare]  end
        include T
        include Comparable.Make(T)
      end

The interface

type ('key, +'value, 'cmp) t = ('key'value'cmpBase.Map.t
type ('k, 'cmp) comparator = (module Comparator.S with type comparator_witness = 'cmp and type t = 'k)
val invariants : (___t ‑> Core_kernel__.Import.bool

Test if invariants of internal AVL search tree hold.

val comparator : ('a_'cmpt ‑> ('a'cmpComparator.t
val empty : ('a'cmpcomparator ‑> ('a'b'cmpt

The empty map.

val singleton : ('a'cmpcomparator ‑> 'a ‑> 'b ‑> ('a'b'cmpt

Map with one (key, data) pair.

val of_alist : ('a'cmpcomparator ‑> ('a * 'b) Core_kernel__.Import.list ‑> [ `Ok of ('a'b'cmpt | `Duplicate_key of 'a ]

Creates map from an association list with unique keys.

val of_alist_or_error : ('a'cmpcomparator ‑> ('a * 'b) Core_kernel__.Import.list ‑> ('a'b'cmpt Or_error.t

Creates map from an association list with unique keys. Returns an error if duplicate 'a keys are found.

val of_alist_exn : ('a'cmpcomparator ‑> ('a * 'b) Core_kernel__.Import.list ‑> ('a'b'cmpt

Creates map from an association list with unique keys. Raises an exception if duplicate 'a keys are found.

val of_hashtbl_exn : ('a'cmpcomparator ‑> ('a'bHashtbl.t ‑> ('a'b'cmpt

of_hashtbl_exn creates a map from bindings present in a hash table. of_hashtbl_exn raises if there are distinct keys a1 and a2 in the table with comparator.compare a1 a2 = 0, which is only possible if the hash-table comparison function is different than comparator.compare. In the common case, the comparison is the same, in which case of_hashtbl_exn does not raise, regardless of the keys present in the table.

val of_alist_multi : ('a'cmpcomparator ‑> ('a * 'b) Core_kernel__.Import.list ‑> ('a'b Core_kernel__.Import.list'cmpt

Creates map from an association list with possibly repeated keys.

val of_alist_fold : ('a'cmpcomparator ‑> ('a * 'b) Core_kernel__.Import.list ‑> init:'c ‑> f:('c ‑> 'b ‑> 'c) ‑> ('a'c'cmpt

Combines an association list into a map, folding together bound values with common keys.

val of_alist_reduce : ('a'cmpcomparator ‑> ('a * 'b) Core_kernel__.Import.list ‑> f:('b ‑> 'b ‑> 'b) ‑> ('a'b'cmpt

Combines an association list into a map, reducing together bound values with common keys.

val of_iteri : ('a'cmpcomparator ‑> iteri:(f:(key:'a ‑> data:'b ‑> Core_kernel__.Import.unit) ‑> Core_kernel__.Import.unit) ‑> [ `Ok of ('a'b'cmpt | `Duplicate_key of 'a ]

of_iteri ~iteri behaves like of_alist, except that instead of taking a concrete datastruture, it takes an iteration function. For instance, to convert a string table into a map: of_iteri (module String) ~f:(Hashtbl.iteri table). It is faster than adding the elements one by one.

Trees

Parallel to the three kinds of map modules Map, Map.Poly, and Key.Map, there are also tree modules Map.Tree, Map.Poly.Tree, and Key.Map.Tree. A tree is a bare representation of a map, without the comparator. Thus tree operations need to obtain the comparator from somewhere. For Map.Poly.Tree and Key.Map.Tree, the comparator is implicit in the module name. For Map.Tree, the comparator must be passed to each operation.

The main advantages of trees over maps are slightly improved space usage (there is no outer container holding the comparator) and the ability to marshal trees, because a tree doesn't contain a closure, the way a map does.

The main disadvantages of using trees are needing to be more explicit about the comparator, and the possibility of accidentally using polymorphic equality on a tree (for which maps dynamically detect failure due to the presence of a closure in the data structure).

module Tree : sig ... end
val to_tree : ('k'v'cmpt ‑> ('k'v'cmpTree.t
val of_tree : ('k'cmpcomparator ‑> ('k'v'cmpTree.t ‑> ('k'v'cmpt

Creates a t from a Tree.t and a Comparator.t. This is an O(n) operation as it must discover the length of the Tree.t.

More interface

val of_sorted_array : ('a'cmpcomparator ‑> ('a * 'b) Core_kernel__.Import.array ‑> ('a'b'cmpt Or_error.t

Creates map from a sorted array of key-data pairs. The input array must be sorted, as given by the relevant comparator (either in ascending or descending order), and must not contain any duplicate keys. If either of these conditions does not hold, an error is returned.

val of_sorted_array_unchecked : ('a'cmpcomparator ‑> ('a * 'b) Core_kernel__.Import.array ‑> ('a'b'cmpt

Like of_sorted_array except it returns a map with broken invariants when an Error would have been returned.

val of_increasing_iterator_unchecked : ('a'cmpcomparator ‑> len:Core_kernel__.Import.int ‑> f:(Core_kernel__.Import.int ‑> 'a * 'b) ‑> ('a'b'cmpt

of_increasing_iterator_unchecked c ~len ~f behaves like of_sorted_array_unchecked c (Array.init len ~f), with the additional restriction that a decreasing order is not supported. The advantage is not requiring you to allocate an intermediate array. f will be called with 0, 1, ... len - 1, in order.

val of_increasing_sequence : ('k'cmpcomparator ‑> ('k * 'v) Sequence.t ‑> ('k'v'cmpt Or_error.t

of_increasing_sequence c seq behaves like of_sorted_array c (Sequence.to_array seq), but does not allocate the intermediate array.

The sequence will be folded over once, and the additional time complexity is O(n).

val is_empty : (___t ‑> Core_kernel__.Import.bool

Tests whether a map is empty or not.

val length : (___t ‑> Core_kernel__.Import.int

length map returns number of elements in map. O(1), but Tree.length is O(n).

val add : ('k'v'cmpt ‑> key:'k ‑> data:'v ‑> ('k'v'cmpt

Returns a new map with the specified new binding; if the key was already bound, its previous binding disappears.

val set : ('k'v'cmpt ‑> key:'k ‑> data:'v ‑> ('k'v'cmpt
val add_multi : ('k'v Core_kernel__.Import.list'cmpt ‑> key:'k ‑> data:'v ‑> ('k'v Core_kernel__.Import.list'cmpt

If key is not present then add a singleton list, otherwise, cons data onto the head of the existing list.

val remove_multi : ('k'v Core_kernel__.Import.list'cmpt ‑> 'k ‑> ('k'v Core_kernel__.Import.list'cmpt

If k is present then remove its head element; if result is empty, remove the key.

val find_multi : ('k'v Core_kernel__.Import.list'cmpt ‑> 'k ‑> 'v Core_kernel__.Import.list

find_multi t key returns t's values for key if key is present in the table, and returns the empty list otherwise.

val change : ('k'v'cmpt ‑> 'k ‑> f:('v Core_kernel__.Import.option ‑> 'v Core_kernel__.Import.option) ‑> ('k'v'cmpt

change t key ~f returns a new map m that is the same as t on all keys except for key, and whose value for key is defined by f, i.e., find m key = f (find t key).

val update : ('k'v'cmpt ‑> 'k ‑> f:('v Core_kernel__.Import.option ‑> 'v) ‑> ('k'v'cmpt

update t key ~f is change t key ~f:(fun o -> Some (f o)).

val find : ('k'v'cmpt ‑> 'k ‑> 'v Core_kernel__.Import.option

Returns the value bound to the given key if it exists, and None otherwise.

val find_exn : ('k'v'cmpt ‑> 'k ‑> 'v

Returns the value bound to the given key, raising Not_found if none such exists.

val find_or_error : ('k'v'cmpt ‑> 'k ‑> 'v Or_error.t
val remove : ('k'v'cmpt ‑> 'k ‑> ('k'v'cmpt

Returns a new map with any binding for the key in question removed.

val mem : ('k_'cmpt ‑> 'k ‑> Core_kernel__.Import.bool

mem map key tests whether map contains a binding for key.

val iter_keys : ('k__t ‑> f:('k ‑> Core_kernel__.Import.unit) ‑> Core_kernel__.Import.unit
val iter : (_'v_t ‑> f:('v ‑> Core_kernel__.Import.unit) ‑> Core_kernel__.Import.unit
val iteri : ('k'v_t ‑> f:(key:'k ‑> data:'v ‑> Core_kernel__.Import.unit) ‑> Core_kernel__.Import.unit
val iter2 : ('k'v1'cmpt ‑> ('k'v2'cmpt ‑> f:(key:'k ‑> data:[ `Left of 'v1 | `Right of 'v2 | `Both of 'v1 * 'v2 ] ‑> Core_kernel__.Import.unit) ‑> Core_kernel__.Import.unit

Iterates two maps side by side. The complexity of this function is O(M+N). If two inputs are [(0, a); (1, a)] and [(1, b); (2, b)], f will be called with [(0, `Left a); (1, `Both (a, b)); (2, `Right b)]

val map : ('k'v1'cmpt ‑> f:('v1 ‑> 'v2) ‑> ('k'v2'cmpt

Returns new map with bound values replaced by the result of f applied to them.

val mapi : ('k'v1'cmpt ‑> f:(key:'k ‑> data:'v1 ‑> 'v2) ‑> ('k'v2'cmpt

Like map, but f takes both key and data as arguments.

val fold : ('k'v_t ‑> init:'a ‑> f:(key:'k ‑> data:'v ‑> 'a ‑> 'a) ‑> 'a

Folds over keys and data in map in increasing order of key.

val fold_right : ('k'v_t ‑> init:'a ‑> f:(key:'k ‑> data:'v ‑> 'a ‑> 'a) ‑> 'a

Folds over keys and data in map in decreasing order of key.

val fold2 : ('k'v1'cmpt ‑> ('k'v2'cmpt ‑> init:'a ‑> f:(key:'k ‑> data:[ `Left of 'v1 | `Right of 'v2 | `Both of 'v1 * 'v2 ] ‑> 'a ‑> 'a) ‑> 'a

Folds over two maps side by side, like iter2.

filter, filteri, filter_keys, filter_map, and filter_mapi run in O(n * lg n) time; they simply accumulate each key & data retained by f into a new map using add.

val filter_keys : ('k'v'cmpt ‑> f:('k ‑> Core_kernel__.Import.bool) ‑> ('k'v'cmpt
val filter : ('k'v'cmpt ‑> f:('v ‑> Core_kernel__.Import.bool) ‑> ('k'v'cmpt
val filteri : ('k'v'cmpt ‑> f:(key:'k ‑> data:'v ‑> Core_kernel__.Import.bool) ‑> ('k'v'cmpt
val filter_map : ('k'v1'cmpt ‑> f:('v1 ‑> 'v2 Core_kernel__.Import.option) ‑> ('k'v2'cmpt

Returns new map with bound values filtered by the result of f applied to them.

val filter_mapi : ('k'v1'cmpt ‑> f:(key:'k ‑> data:'v1 ‑> 'v2 Core_kernel__.Import.option) ‑> ('k'v2'cmpt

Like filter_map, but function takes both key and data as arguments.

val partition_mapi : ('k'v1'cmpt ‑> f:(key:'k ‑> data:'v1 ‑> [ `Fst of 'v2 | `Snd of 'v3 ]) ‑> ('k'v2'cmpt * ('k'v3'cmpt

partition_mapi t ~f returns two new ts, with each key in t appearing in exactly one of the result maps depending on its mapping in f.

val partition_map : ('k'v1'cmpt ‑> f:('v1 ‑> [ `Fst of 'v2 | `Snd of 'v3 ]) ‑> ('k'v2'cmpt * ('k'v3'cmpt

partition_map t ~f = partition_mapi t ~f:(fun ~key:_ ~data -> f data)

val partitioni_tf : ('k'v'cmpt ‑> f:(key:'k ‑> data:'v ‑> Core_kernel__.Import.bool) ‑> ('k'v'cmpt * ('k'v'cmpt
     partitioni_tf t ~f
     =
     partition_mapi t ~f:(fun ~key ~data ->
       if f ~key ~data
       then `Fst data
       else `Snd data)
val partition_tf : ('k'v'cmpt ‑> f:('v ‑> Core_kernel__.Import.bool) ‑> ('k'v'cmpt * ('k'v'cmpt

partition_tf t ~f = partitioni_tf t ~f:(fun ~key:_ ~data -> f data)

val compare_direct : ('v ‑> 'v ‑> Core_kernel__.Import.int) ‑> ('k'v'cmpt ‑> ('k'v'cmpt ‑> Core_kernel__.Import.int

Total ordering between maps. The first argument is a total ordering used to compare data associated with equal keys in the two maps.

val hash_fold_direct : 'k Core_kernel__.Import.Hash.folder ‑> 'v Core_kernel__.Import.Hash.folder ‑> ('k'v'cmpt Core_kernel__.Import.Hash.folder

Hash function: a building block to use when hashing data structures containing maps in them. hash_fold_direct hash_fold_key is compatible with compare_direct iff hash_fold_key is compatible with (comparator m).compare of the map m being hashed.

val equal : ('v ‑> 'v ‑> Core_kernel__.Import.bool) ‑> ('k'v'cmpt ‑> ('k'v'cmpt ‑> Core_kernel__.Import.bool

equal cmp m1 m2 tests whether the maps m1 and m2 are equal, that is, contain equal keys and associate them with equal data. cmp is the equality predicate used to compare the data associated with the keys.

val keys : ('k__t ‑> 'k Core_kernel__.Import.list

Returns list of keys in map.

val data : (_'v_t ‑> 'v Core_kernel__.Import.list

Returns list of data in map.

val to_alist : ?⁠key_order:[ `Increasing | `Decreasing ] ‑> ('k'v_t ‑> ('k * 'v) Core_kernel__.Import.list

Creates association list from map.

val validate : name:('k ‑> Core_kernel__.Import.string) ‑> 'v Core_kernel__.Import.Validate.check ‑> ('k'v_t Core_kernel__.Import.Validate.check

Additional operations on maps

val merge : ('k'v1'cmpt ‑> ('k'v2'cmpt ‑> f:(key:'k ‑> [ `Left of 'v1 | `Right of 'v2 | `Both of 'v1 * 'v2 ] ‑> 'v3 Core_kernel__.Import.option) ‑> ('k'v3'cmpt

Merges two maps. The runtime is O(length(t1) + length(t2)). In particular, you shouldn't use this function to merge a list of maps. Consider using merge_skewed instead.

val merge_skewed : ('k'v'cmpt ‑> ('k'v'cmpt ‑> combine:(key:'k ‑> 'v ‑> 'v ‑> 'v) ‑> ('k'v'cmpt

A special case of merge, merge_skewed t1 t2 is a map containing all the bindings of t1 and t2. Bindings that appear in both t1 and t2 are merged using the combine function. In a call combine ~key v1 v2 the value v1 comes from t1 and v2 from t2.

The runtime of merge_skewed is O(l1 * log(l2)), where l1 is the length of the smaller map and l2 the length of the larger map. This is likely to be faster than merge when one of the maps is a lot smaller, or when you merge a list of maps.

module Symmetric_diff_element : sig ... end
val symmetric_diff : ('k'v'cmpt ‑> ('k'v'cmpt ‑> data_equal:('v ‑> 'v ‑> Core_kernel__.Import.bool) ‑> ('k'vSymmetric_diff_element.t Sequence.t

symmetric_diff t1 t2 ~data_equal returns a list of changes between t1 and t2. It is intended to be efficient in the case where t1 and t2 share a large amount of structure. The keys in the output sequence will be in sorted order.

val min_elt : ('k'v_t ‑> ('k * 'v) Core_kernel__.Import.option

min_elt map returns Some (key, data) pair corresponding to the minimum key in map, None if map is empty.

val min_elt_exn : ('k'v_t ‑> 'k * 'v
val max_elt : ('k'v_t ‑> ('k * 'v) Core_kernel__.Import.option

max_elt map returns Some (key, data) pair corresponding to the maximum key in map, and None if map is empty.

val max_elt_exn : ('k'v_t ‑> 'k * 'v

The following functions have the same semantics as similar functions in Core_kernel.List.

val for_all : ('k'v_t ‑> f:('v ‑> Core_kernel__.Import.bool) ‑> Core_kernel__.Import.bool
val for_alli : ('k'v_t ‑> f:(key:'k ‑> data:'v ‑> Core_kernel__.Import.bool) ‑> Core_kernel__.Import.bool
val exists : ('k'v_t ‑> f:('v ‑> Core_kernel__.Import.bool) ‑> Core_kernel__.Import.bool
val existsi : ('k'v_t ‑> f:(key:'k ‑> data:'v ‑> Core_kernel__.Import.bool) ‑> Core_kernel__.Import.bool
val count : ('k'v_t ‑> f:('v ‑> Core_kernel__.Import.bool) ‑> Core_kernel__.Import.int
val counti : ('k'v_t ‑> f:(key:'k ‑> data:'v ‑> Core_kernel__.Import.bool) ‑> Core_kernel__.Import.int
val split : ('k'v'cmpt ‑> 'k ‑> ('k'v'cmpt * ('k * 'v) Core_kernel__.Import.option * ('k'v'cmpt

split t key returns a map of keys strictly less than key, the mapping of key if any, and a map of keys strictly greater than key.

Runtime is O(m + log n) where n is the size of the input map, and m is the size of the smaller of the two output maps. The O(m) term is due to the need to calculate the length of the output maps. *

val append : lower_part:('k'v'cmpt ‑> upper_part:('k'v'cmpt ‑> [ `Ok of ('k'v'cmpt | `Overlapping_key_ranges ]

append ~lower_part ~upper_part returns `Ok map where map contains all the (key, value) pairs from the two input maps if all the keys from lower_part are less than all the keys from upper_part. Otherwise it returns `Overlapping_key_ranges.

Runtime is O(log n) where n is the size of the larger input map. This can be significantly faster than Map.merge or repeated Map.add.

      assert (match Map.append ~lower_part ~upper_part with
        | `Ok whole_map ->
          whole_map
          = Map.(of_alist_exn (List.append (to_alist lower_part) (to_alist upper_part)))
        | `Overlapping_key_ranges -> true);
val subrange : ('k'v'cmpt ‑> lower_bound:'k Maybe_bound.t ‑> upper_bound:'k Maybe_bound.t ‑> ('k'v'cmpt

subrange t ~lower_bound ~upper_bound returns a map containing all the entries from t whose keys lie inside the interval indicated by ~lower_bound and ~upper_bound. If this interval is empty, an empty map is returned.

Runtime is O(m + log n) where n is the size of the input map, and m is the size of the output map. The O(m) term is due to the need to calculate the length of the output map.

val fold_range_inclusive : ('k'v'cmpt ‑> min:'k ‑> max:'k ‑> init:'a ‑> f:(key:'k ‑> data:'v ‑> 'a ‑> 'a) ‑> 'a

fold_range_inclusive t ~min ~max ~init ~f folds f (with initial value ~init) over all keys (and their associated values) that are in the range [min, max] (inclusive).

val range_to_alist : ('k'v'cmpt ‑> min:'k ‑> max:'k ‑> ('k * 'v) Core_kernel__.Import.list

range_to_alist t ~min ~max returns an associative list of the elements whose keys lie in [min, max] (inclusive), with the smallest key being at the head of the list.

val closest_key : ('k'v'cmpt ‑> [ `Greater_or_equal_to | `Greater_than | `Less_or_equal_to | `Less_than ] ‑> 'k ‑> ('k * 'v) Core_kernel__.Import.option

closest_key t dir k returns the (key, value) pair in t with key closest to k, which satisfies the given inequality bound.

For example, closest_key t `Less_than k would be the pair with the closest key to k where key < k.

to_sequence can be used to get the same results as closest_key. It is less efficient for individual lookups but more efficient for finding many elements starting at some value.

val nth : ('k'v_t ‑> Core_kernel__.Import.int ‑> ('k * 'v) Core_kernel__.Import.option

nth t n finds the (key, value) pair of rank n (i.e., such that there are exactly n keys strictly less than the found key), if one exists. O(log(length t) + n) time.

val nth_exn : ('k'v_t ‑> Core_kernel__.Import.int ‑> 'k * 'v
val rank : ('k'v'cmpt ‑> 'k ‑> Core_kernel__.Import.int Core_kernel__.Import.option

rank t k if k is in t, returns the number of keys strictly less than k in t, otherwise None.

val to_sequence : ?⁠order:[ `Increasing_key | `Decreasing_key ] ‑> ?⁠keys_greater_or_equal_to:'k ‑> ?⁠keys_less_or_equal_to:'k ‑> ('k'v'cmpt ‑> ('k * 'v) Sequence.t

to_sequence ?order ?keys_greater_or_equal_to ?keys_less_or_equal_to t gives a sequence of key-value pairs between keys_less_or_equal_to and keys_greater_or_equal_to inclusive, presented in order. If keys_greater_or_equal_to > keys_less_or_equal_to, the sequence is empty. Cost is O(log n) up front and amortized O(1) to produce each element.

val gen : ('k'cmpcomparator ‑> 'k Quickcheck.Generator.t ‑> 'v Quickcheck.Generator.t ‑> ('k'v'cmpt Quickcheck.Generator.t
val obs : 'k Quickcheck.Observer.t ‑> 'v Quickcheck.Observer.t ‑> ('k'v'cmpt Quickcheck.Observer.t
val shrinker : 'k Quickcheck.Shrinker.t ‑> 'v Quickcheck.Shrinker.t ‑> ('k'v'cmpt Quickcheck.Shrinker.t

This shrinker and the other shrinkers for maps and trees produce a shrunk value by dropping a key-value pair, shrinking a key or shrinking a value. A shrunk key will override an existing key's value.

Which Map module should you use?

The map types and operations appear in three places:

where Key is any module defining values that can be used as keys of a map, like Int, String, etc. To add this functionality to an arbitrary module, use the Comparable.Make functor.

You should use Map for functions that access existing maps, like find, mem, add, fold, iter, and to_alist. For functions that create maps, like empty, singleton, and of_alist, strive to use the corresponding Key.Map function, which will use the comparison function specifically for Key. As a last resort, if you don't have easy access to a comparison function for the keys in your map, use Map.Poly to create the map. This will use OCaml's built-in polymorphic comparison to compare keys, with all the usual performance and robustness problems that entails.

Interface design details

An instance of the map type is determined by the types of the map's keys and values, and the comparison function used to order the keys:

type ('key, 'value, 'cmp) Map.t

'cmp is a phantom type uniquely identifying the comparison function, as generated by Comparator.Make.

Map.Poly supports arbitrary key and value types, but enforces that the comparison function used to order the keys is polymorphic comparison. Key.Map has a fixed key type and comparison function, and supports arbitrary values.

     type ('key, 'value) Map.Poly.t = ('key , 'value, Comparator.Poly.t) Map.t
     type 'value Key.Map.t          = (Key.t, 'value, Key.comparator   ) Map.t

The same map operations exist in Map, Map.Poly, and Key.Map, albeit with different types. For example:

     val Map.length      : (_, _, _) Map.t   -> int
     val Map.Poly.length : (_, _) Map.Poly.t -> int
     val Key.Map.length  : _ Key.Map.t       -> int

Because Map.Poly.t and Key.Map.t are exposed as instances of the more general Map.t type, one can use Map.length on any map. The same is true for all of the functions that access an existing map, such as add, change, find, fold, iter, map, to_alist, etc.

Depending on the number of type variables N, the type of accessor (resp. creator) functions is defined in the module type AccessorsN (CreatorsN) in Map_intf. Also for creators, when the comparison function is not fixed, i.e., the 'cmp variable of Map.t is free, we need to pass a comparator to the function creating the map. The module type is called Creators3_with_comparator. There is also a module type Accessors3_with_comparator in addition to Accessors3 which used for trees since the comparator is not known.

module Using_comparator : sig ... end
module Poly : sig ... end with type ('a, 'b, 'c) map = ('a'b'ct
module type Key_plain = Map_intf.Key_plain
module type Key = Map_intf.Key
module type Key_binable = Map_intf.Key_binable
module type S_plain = Map_intf.S_plain
module type S = Map_intf.S
module type S_binable = Map_intf.S_binable
module Make_plain : functor (Key : Key_plain) -> S_plain with type Key.t = Key.t
module Make_plain_using_comparator : functor (Key : sig ... end) -> S_plain with type Key.t = Key.t with type Key.comparator_witness = Key.comparator_witness
module Make : functor (Key : Key) -> S with type Key.t = Key.t
module Make_using_comparator : functor (Key : sig ... end) -> S with type Key.t = Key.t with type Key.comparator_witness = Key.comparator_witness
module Make_binable : functor (Key : Key_binable) -> S_binable with type Key.t = Key.t
module Make_binable_using_comparator : functor (Key : sig ... end) -> S_binable with type Key.t = Key.t with type Key.comparator_witness = Key.comparator_witness
module Stable : sig ... end

The following functors may be used to define stable modules