The type of key is replaced by a type constructor 'k key. Because of that, most higher-order arguments require higher-ranking polymorphism, and we provide records that allows to pass them as arguments (e.g. polyiter, polymap, polyunion, etc.)
The type of the map (t) is still parameterized by an argument ('m t)
The type of value depend on both the type of the key and the type of the map, hence the type ('k,'m) value.
The type of some return values, like key-value pairs, must be concealed existentially, hence the KeyValue constructor.
Branching bit contains only one bit set; the corresponding mask is (branching_bit - 1). The prefixes are normalized: the bits below the branching bit are set to zero (i.e. prefix & (branching_bit - 1) = 0).
This makes the map nodes accessible to the pattern matching algorithm; this corresponds 1:1 to the SimpleNode implementation. This just needs to be copy-and-pasted for every node type.
pop_maximum m returns None if is_empty m, or Some(key,value,m') where (key,value) = max_binding m and m' = remove m key. O(log(n)) complexity.
val insert :
'akey->(('a, 'map)value option->('a, 'map)value)->'mapt->'mapt
insert key f map modifies or insert an element of the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.
val update :
'akey->(('a, 'map)value option->('a, 'map)value option)->'mapt->'mapt
update key f map modifies, insert, or remove an element from the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. It returns None if the element should be removed O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.
val add : 'keykey->('key, 'map)value->'mapt->'mapt
Unconditionally adds a value in the map (independently from whether the old value existed). O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.
Iterators
val split : 'keykey->'mapt->'mapt * ('key, 'map)value option * 'mapt
split key map splits the map into:
submap of map whose keys are smaller than key
value associated to key (if present)
submap of map whose keys are bigger than key Where the order is given by Key.to_int.
val fold : ('acc, 'map)polyfold->'mapt->'acc->'acc
fold f m acc returns f.f key_n value_n (... (f.f key_1 value_1 acc)) where (key_1, value_1) ... (key_n, value_n) are the bindings of m, in the order given by Key.to_int.
for_all f m checks that f holds on all bindings of m7 Short-circuiting.
In the following, the *no_share function allows taking arguments of different types (but cannot share subtrees of the map), while the default functions attempt to preserve and benefit from sharing the subtrees (using physical equality to detect sharing).
val filter_map_no_share : ('map1, 'map2)polyfilter_map->'map1t->'map2t
filter_map m f and filter_map_no_share m f remove the bindings (k,v) for which f.f k v is None, and replaces the bindings (k,v) for which f.f k v is Some v' by (k,v'). Bindings are examined in the order given by Key.to_int.
type'map polypretty = {
f : 'a. Stdlib.Format.formatter ->'akey->('a, 'map)value-> unit;
}
val pretty :
?pp_sep:(Stdlib.Format.formatter ->unit -> unit)->'mappolypretty->Stdlib.Format.formatter ->'mapt->
unit
Pretty-prints a map using the given formatter. pp_sep is called once between each binding, it defaults to Format.pp_print_cut. Bindings are printed in the order given by Key.to_int
Functions on pairs of maps
type('map1, 'map2) polysame_domain_for_all2 = {
f : 'a. 'akey->('a, 'map1)value->('a, 'map2)value-> bool;
reflexive_same_domain_for_all2 f m1 m2 is true if and only if
m1 and m2 have the same domain (set of keys)
for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds @assumes f.f is reflexive, i.e. f.f k v v = true to skip calls to equal subtrees. Calls f.f in ascending order of Key.to_int. Exits early if the domains mismatch.
It is useful to implement equality on maps:
let equal m1 m2 = reflexive_same_domain_for_all2
{ f = fun _ v1 v2 -> Value.equal v1 v2}
m1 m2
nonreflexive_same_domain_for_all2 f m1 m2 is the same as reflexive_same_domain_for_all2, but doesn't assume f.f is reflexive. It thus calls f.f on every binding, in ascending order of Key.to_int. Exits early if the domains mismatch.
reflexive_subset_domain_for_all2 f m1 m2 is true if and only if
m1's domain is a subset of m2's. (all keys defined in m1 are also defined in m2)
for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds @assumes f.f is reflexive, i.e. f.f k v v = true to skip calls to equal subtrees. Calls f.f in ascending order of Key.to_int. Exits early if the domains mismatch.
val idempotent_union : ('a, 'a, 'a)polyunion->'at->'at->'at
idempotent_union f map1 map2 returns a map whose keys is the union of the keys of map1 and map2. f.f is used to combine the values of keys mapped in both maps. @assumes f.f idempotent (i.e. f key value value == value) f.f is called in the order given by Key.to_int. f.f is never called on physically equal values. Preserves physical equality as much as possible. Complexity is O(log(n)*Delta) where Delta is the number of different keys between map1 and map2.
val idempotent_inter : ('a, 'a, 'a)polyinter->'at->'at->'at
idempotent_inter f map1 map2 returns a map whose keys is the intersection of the keys of map1 and map2. f.f is used to combine the values a key is mapped in both maps. @assumes f.f idempotent (i.e. f key value value == value) f.f is called in the order given by Key.to_int. f.f is never called on physically equal values. Preserves physical equality as much as possible. Complexity is O(log(n)*Delta) where Delta is the number of different keys between map1 and map2.
val nonidempotent_inter_no_share :
('a, 'b, 'c)polyinter->'at->'bt->'ct
nonidempotent_inter_no_share f map1 map2 is the same as idempotent_inter but doesn't preverse physical equality, doesn't assume f.f is idempotent, and can change the type of values. f.f is called on every shared binding. f.f is called in increasing order of keys. O(n) complexity
type('map1, 'map2, 'map3) polyinterfilter = {
f : 'a. 'akey->('a, 'map1)value->('a, 'map2)value->('a, 'map3)value option;
}
val idempotent_inter_filter :
('a, 'a, 'a)polyinterfilter->'at->'at->'at
idempotent_inter_filter f map1 map2 is the same as idempotent_inter but f.f can return None to remove a binding from the resutling map.
type('map1, 'map2, 'map3) polymerge = {
f : 'a. 'akey->('a, 'map1)value option->('a, 'map2)value option->('a, 'map3)value option;
}
val slow_merge :
('map1, 'map2, 'map3)polymerge->'map1t->'map2t->'map3t