HORIZON HASKELLDocslts/ghc-9.10.xc74966e2026-09-27Search names, modules, packages, or :: a typeCtrl K

GHC 9.10.3 · lts/ghc-9.10.x · c74966e · 2026-09-27

Moduleunordered-containers-0.2.21Haskell2010

Data.HashMap.Internal

WARNING

This module is considered internal.

The Package Versioning Policy does not apply.

The contents of this module may change in any way whatsoever and without any warning between minor versions of this package.

Authors importing this module are expected to track development closely.

  • 6 types
  • 89 values
datadata HashMap k v
#

A map from keys to values. A map cannot contain duplicate keys; each key can map to at most one value.

Constructors

  • Empty

    Invariants:

    • Empty is not a valid sub-node. It can only appear at the root. (INV1)

  • BitmapIndexed !Bitmap !(Array (HashMap k v))

    Invariants:

    • Only the lower maxChildren bits of the Bitmap may be set. The remaining upper bits must be 0. (INV2)

    • The array of a BitmapIndexed node stores at least 1 and at most maxChildren - 1 sub-nodes. (INV3)

    • The number of sub-nodes is equal to the number of 1-bits in its Bitmap. (INV4)

    • If a BitmapIndexed node has only one sub-node, this sub-node must be a BitmapIndexed or a Full node. (INV5)

  • Leaf !Hash !(Leaf k v)

    Invariants:

    • The location of a Leaf or Collision node in the tree must be compatible with its Hash. (INV6) (TODO: Document this properly (#425))

    • The Hash of a Leaf node must be the hash of its key. (INV7)

  • Full !(Array (HashMap k v))

    Invariants:

  • Collision !Hash !(Array (Leaf k v))

    Invariants:

    • The location of a Leaf or Collision node in the tree must be compatible with its Hash. (INV6) (TODO: Document this properly (#425))

    • The array of a Collision node must contain at least two sub-nodes. (INV9)

    • The hash of each key in a Collision node must be the one stored in the node. (INV7)

    • No two keys stored in a Collision can be equal according to their Eq instance. (INV10)

Instances27Bifoldable, Eq2, Ord2, Show2, NFData2, Hashable2, …
  • Bifoldable HashMapDefined in unordered-containers-0.2.21 · Data.HashMap.Internal
  • Eq2 HashMapDefined in unordered-containers-0.2.21 · Data.HashMap.Internal
  • Ord2 HashMapDefined in unordered-containers-0.2.21 · Data.HashMap.Internal
  • Show2 HashMapDefined in unordered-containers-0.2.21 · Data.HashMap.Internal
  • NFData2 HashMapDefined in unordered-containers-0.2.21 · Data.HashMap.Internal
  • Hashable2 HashMapDefined in unordered-containers-0.2.21 · Data.HashMap.Internal
  • (Lift k, Lift v) => Lift (HashMap k v)Defined in unordered-containers-0.2.21 · Data.HashMap.Internal
  • Functor (HashMap k)Defined in unordered-containers-0.2.21 · Data.HashMap.Internal
  • Foldable (HashMap k)Defined in unordered-containers-0.2.21 · Data.HashMap.Internal
  • Traversable (HashMap k)Defined in unordered-containers-0.2.21 · Data.HashMap.Internal
  • Eq k => Eq1 (HashMap k)Defined in unordered-containers-0.2.21 · Data.HashMap.Internal
  • Ord k => Ord1 (HashMap k)Defined in unordered-containers-0.2.21 · Data.HashMap.Internal
  • (Hashable k, Read k) => Read1 (HashMap k)Defined in unordered-containers-0.2.21 · Data.HashMap.Internal
  • Show k => Show1 (HashMap k)Defined in unordered-containers-0.2.21 · Data.HashMap.Internal
  • NFData k => NFData1 (HashMap k)Defined in unordered-containers-0.2.21 · Data.HashMap.Internal
  • Hashable k => Hashable1 (HashMap k)Defined in unordered-containers-0.2.21 · Data.HashMap.Internal
  • Hashable k => IsList (HashMap k v)Defined in unordered-containers-0.2.21 · Data.HashMap.Internal
  • (Eq k, Eq v) => Eq (HashMap k v)Defined in unordered-containers-0.2.21 · Data.HashMap.Internal

    Note that, in the presence of hash collisions, equal HashMaps may behave differently, i.e. extensionality may be violated:

    Example2 expressions
    data D = A | B deriving (Eq, Show)instance Hashable D where hashWithSalt salt _d = salt
    Example2 expressions
    x = fromList [(A,1), (B,2)]y = fromList [(B,2), (A,1)]
    Example3 expressions
    x == yTruetoList x[(A,1),(B,2)]toList y[(B,2),(A,1)]

    In general, the lack of extensionality can be observed with any function that depends on the key ordering, such as folds and traversals.

  • (Data k, Data v, Hashable k) => Data (HashMap k v)Defined in unordered-containers-0.2.21 · Data.HashMap.Internal
  • (Ord k, Ord v) => Ord (HashMap k v)Defined in unordered-containers-0.2.21 · Data.HashMap.Internal

    The ordering is total and consistent with the Eq instance. However, nothing else about the ordering is specified, and it may change from version to version of either this package or of hashable.

  • (Hashable k, Read k, Read e) => Read (HashMap k e)Defined in unordered-containers-0.2.21 · Data.HashMap.Internal
  • (Show k, Show v) => Show (HashMap k v)Defined in unordered-containers-0.2.21 · Data.HashMap.Internal
  • Hashable k => Semigroup (HashMap k v)Defined in unordered-containers-0.2.21 · Data.HashMap.Internal

    <> = union

    If a key occurs in both maps, the mapping from the first will be the mapping in the result.

    Examples
    Example1 expression
    fromList [(1,'a'),(2,'b')] <> fromList [(2,'c'),(3,'d')]fromList [(1,'a'),(2,'b'),(3,'d')]
  • Hashable k => Monoid (HashMap k v)Defined in unordered-containers-0.2.21 · Data.HashMap.Internal

    mempty = empty

    mappend = union

    If a key occurs in both maps, the mapping from the first will be the mapping in the result.

    Examples
    Example1 expression
    mappend (fromList [(1,'a'),(2,'b')]) (fromList [(2,'c'),(3,'d')])fromList [(1,'a'),(2,'b'),(3,'d')]
  • (NFData k, NFData v) => NFData (HashMap k v)Defined in unordered-containers-0.2.21 · Data.HashMap.Internal
  • (Hashable k, Hashable v) => Hashable (HashMap k v)Defined in unordered-containers-0.2.21 · Data.HashMap.Internal
  • type Item (HashMap k v) = (k, v)Defined in unordered-containers-0.2.21 · Data.HashMap.Internal
datadata Leaf k v
#

Constructors

  • L !k v
Instances5NFData2, Lift, NFData1, Eq, NFData
  • NFData2 LeafDefined in unordered-containers-0.2.21 · Data.HashMap.Internal
  • (Lift k, Lift v) => Lift (Leaf k v)Defined in unordered-containers-0.2.21 · Data.HashMap.Internal
  • NFData k => NFData1 (Leaf k)Defined in unordered-containers-0.2.21 · Data.HashMap.Internal
  • (Eq k, Eq v) => Eq (Leaf k v)Defined in unordered-containers-0.2.21 · Data.HashMap.Internal
  • (NFData k, NFData v) => NFData (Leaf k v)Defined in unordered-containers-0.2.21 · Data.HashMap.Internal

Construction

2 declarations

Basic interface

19 declarations
valuesize :: HashMap k v -> Int
#

O(n) Return the number of key-value mappings in this map.

valuelookup :: Hashable k => k -> HashMap k v -> Maybe v
#

O(\log n) Return the value to which the specified key is mapped, or Nothing if this map contains no mapping for the key.

value(!?) :: Hashable k => HashMap k v -> k -> Maybe v
#

O(\log n) Return the value to which the specified key is mapped, or Nothing if this map contains no mapping for the key.

This is a flipped version of lookup.

valuefindWithDefault
  1. :: Hashable k
  2. => v

    Default value to return.

  3. -> k
  4. -> HashMap k v
  5. -> v
#

O(\log n) Return the value to which the specified key is mapped, or the default value if this map contains no mapping for the key.

valuelookupDefault
  1. :: Hashable k
  2. => v

    Default value to return.

  3. -> k
  4. -> HashMap k v
  5. -> v
#

O(\log n) Return the value to which the specified key is mapped, or the default value if this map contains no mapping for the key.

DEPRECATED: lookupDefault is deprecated as of version 0.2.11, replaced by findWithDefault.

value(!) :: (Hashable k, HasCallStack) => HashMap k v -> k -> v
#

O(\log n) Return the value to which the specified key is mapped. Calls error if this map contains no mapping for the key.

valuelookupKey :: Hashable k => k -> HashMap k v -> Maybe k
#

O(\log n) For a given key, return the equal key stored in the map, if present, otherwise return Nothing.

This function can be used for interning, i.e. to reduce memory usage.

valueinsert :: Hashable k => k -> v -> HashMap k v -> HashMap k v
#

O(\log n) Associate the specified value with the specified key in this map. If this map previously contained a mapping for the key, the old value is replaced.

valueinsertWith
  1. :: Hashable k
  2. => v -> v -> v
  3. -> k
  4. -> v
  5. -> HashMap k v
  6. -> HashMap k v
#

O(\log n) Associate the value with the key in this map. If this map previously contained a mapping for the key, the old value is replaced by the result of applying the given function to the new and old value. Example:

insertWith f k v map
  where f new old = new + old
valueadjust :: Hashable k => (v -> v) -> k -> HashMap k v -> HashMap k v
#

O(\log n) Adjust the value tied to a given key in this map only if it is present. Otherwise, leave the map alone.

valueupdate :: Hashable k => (a -> Maybe a) -> k -> HashMap k a -> HashMap k a
#

O(\log n) The expression (update f k map) updates the value x at k (if it is in the map). If (f x) is Nothing, the element is deleted. If it is (Just y), the key k is bound to the new value y.

valueisSubmapOf :: (Hashable k, Eq v) => HashMap k v -> HashMap k v -> Bool
#

O(n \log m) Inclusion of maps. A map is included in another map if the keys are subsets and the corresponding values are equal:

isSubmapOf m1 m2 = keys m1 `isSubsetOf` keys m2 &&
                   and [ v1 == v2 | (k1,v1) <- toList m1; let v2 = m2 ! k1 ]
Examples
Example1 expression
fromList [(1,'a')] `isSubmapOf` fromList [(1,'a'),(2,'b')]True
Example1 expression
fromList [(1,'a'),(2,'b')] `isSubmapOf` fromList [(1,'a')]False
valueisSubmapOfBy
  1. :: Hashable k
  2. => v1 -> v2 -> Bool
  3. -> HashMap k v1
  4. -> HashMap k v2
  5. -> Bool
#

O(n \log m) Inclusion of maps with value comparison. A map is included in another map if the keys are subsets and if the comparison function is true for the corresponding values:

isSubmapOfBy cmpV m1 m2 = keys m1 `isSubsetOf` keys m2 &&
                          and [ v1 `cmpV` v2 | (k1,v1) <- toList m1; let v2 = m2 ! k1 ]
Examples
Example1 expression
isSubmapOfBy (<=) (fromList [(1,'a')]) (fromList [(1,'b'),(2,'c')])True
Example1 expression
isSubmapOfBy (<=) (fromList [(1,'b')]) (fromList [(1,'a'),(2,'c')])False

Combine

0 declarations

Union

valueunion :: Eq k => HashMap k v -> HashMap k v -> HashMap k v
#

O(n+m) The union of two maps. If a key occurs in both maps, the mapping from the first will be the mapping in the result.

Examples
Example1 expression
union (fromList [(1,'a'),(2,'b')]) (fromList [(2,'c'),(3,'d')])fromList [(1,'a'),(2,'b'),(3,'d')]
valueunionWith
  1. :: Eq k
  2. => v -> v -> v
  3. -> HashMap k v
  4. -> HashMap k v
  5. -> HashMap k v
#

O(n+m) The union of two maps. If a key occurs in both maps, the provided function (first argument) will be used to compute the result.

valueunionWithKey
  1. :: Eq k
  2. => k -> v -> v -> v
  3. -> HashMap k v
  4. -> HashMap k v
  5. -> HashMap k v
#

O(n+m) The union of two maps. If a key occurs in both maps, the provided function (first argument) will be used to compute the result.

valueunions :: Eq k => [HashMap k v] -> HashMap k v
#

Construct a set containing all elements from a list of sets.

Compose

valuecompose :: Hashable b => HashMap b c -> HashMap a b -> HashMap a c
#

Given maps bc and ab, relate the keys of ab to the values of bc, by using the values of ab as keys for lookups in bc.

Complexity: O (n * \log(m)) , where m is the size of the first argument

Example1 expression
compose (fromList [('a', "A"), ('b', "B")]) (fromList [(1,'a'),(2,'b'),(3,'z')])fromList [(1,"A"),(2,"B")]
(compose bc ab !?) = (bc !?) <=< (ab !?)

Transformations

4 declarations
valuemap :: (v1 -> v2) -> HashMap k v1 -> HashMap k v2
#

O(n) Transform this map by applying a function to every value.

valuemapWithKey :: (k -> v1 -> v2) -> HashMap k v1 -> HashMap k v2
#

O(n) Transform this map by applying a function to every value.

valuetraverseWithKey
  1. :: Applicative f
  2. => k -> v1 -> f v2
  3. -> HashMap k v1
  4. -> f (HashMap k v2)
#

O(n) Perform an Applicative action for each key-value pair in a HashMap and produce a HashMap of all the results.

Note: the order in which the actions occur is unspecified. In particular, when the map contains hash collisions, the order in which the actions associated with the keys involved will depend in an unspecified way on their insertion order.

valuemapKeys :: Hashable k2 => (k1 -> k2) -> HashMap k1 v -> HashMap k2 v
#

O(n). mapKeys f s is the map obtained by applying f to each key of s.

The size of the result may be smaller if f maps two or more distinct keys to the same new key. In this case there is no guarantee which of the associated values is chosen for the conflicting key.

Example3 expressions
mapKeys (+ 1) (fromList [(5,"a"), (3,"b")])fromList [(4,"b"),(6,"a")]mapKeys (\ _ -> 1) (fromList [(1,"b"), (2,"a"), (3,"d"), (4,"c")])fromList [(1,"c")]mapKeys (\ _ -> 3) (fromList [(1,"b"), (2,"a"), (3,"d"), (4,"c")])fromList [(3,"c")]

Difference and intersection

8 declarations
valuedifferenceWith
  1. :: Hashable k
  2. => v -> w -> Maybe v
  3. -> HashMap k v
  4. -> HashMap k w
  5. -> HashMap k v
#

O(n \log m) Difference with a combining function. When two equal keys are encountered, the combining function is applied to the values of these keys. If it returns Nothing, the element is discarded (proper set difference). If it returns (Just y), the element is updated with a new value y.

valuedifferenceWithKey
  1. :: Eq k
  2. => k -> v -> w -> Maybe v
  3. -> HashMap k v
  4. -> HashMap k w
  5. -> HashMap k v
#

O(n \log m) Difference with a combining function. When two equal keys are encountered, the combining function is applied to the values of these keys. If it returns Nothing, the element is discarded (proper set difference). If it returns (Just y), the element is updated with a new value y.

valueintersectionWith
  1. :: Eq k
  2. => v1 -> v2 -> v3
  3. -> HashMap k v1
  4. -> HashMap k v2
  5. -> HashMap k v3
#

O(n \log m) Intersection of two maps. If a key occurs in both maps the provided function is used to combine the values from the two maps.

valueintersectionWithKey
  1. :: Eq k
  2. => k -> v1 -> v2 -> v3
  3. -> HashMap k v1
  4. -> HashMap k v2
  5. -> HashMap k v3
#

O(n \log m) Intersection of two maps. If a key occurs in both maps the provided function is used to combine the values from the two maps.

valuedisjoint :: Eq k => HashMap k a -> HashMap k b -> Bool
#

O(n \log m) Check whether the key sets of two maps are disjoint (i.e., their intersection is empty).

xs `disjoint` ys = null (xs `intersection` ys)

Folds

9 declarations
valuefoldr' :: (v -> a -> a) -> a -> HashMap k v -> a
#

O(n) Reduce this map by applying a binary operator to all elements, using the given starting value (typically the right-identity of the operator). Each application of the operator is evaluated before using the result in the next application. This function is strict in the starting value.

valuefoldl' :: (a -> v -> a) -> a -> HashMap k v -> a
#

O(n) Reduce this map by applying a binary operator to all elements, using the given starting value (typically the left-identity of the operator). Each application of the operator is evaluated before using the result in the next application. This function is strict in the starting value.

valuefoldrWithKey' :: (k -> v -> a -> a) -> a -> HashMap k v -> a
#

O(n) Reduce this map by applying a binary operator to all elements, using the given starting value (typically the right-identity of the operator). Each application of the operator is evaluated before using the result in the next application. This function is strict in the starting value.

valuefoldlWithKey' :: (a -> k -> v -> a) -> a -> HashMap k v -> a
#

O(n) Reduce this map by applying a binary operator to all elements, using the given starting value (typically the left-identity of the operator). Each application of the operator is evaluated before using the result in the next application. This function is strict in the starting value.

valuefoldr :: (v -> a -> a) -> a -> HashMap k v -> a
#

O(n) Reduce this map by applying a binary operator to all elements, using the given starting value (typically the right-identity of the operator).

valuefoldl :: (a -> v -> a) -> a -> HashMap k v -> a
#

O(n) Reduce this map by applying a binary operator to all elements, using the given starting value (typically the left-identity of the operator).

valuefoldrWithKey :: (k -> v -> a -> a) -> a -> HashMap k v -> a
#

O(n) Reduce this map by applying a binary operator to all elements, using the given starting value (typically the right-identity of the operator).

valuefoldlWithKey :: (a -> k -> v -> a) -> a -> HashMap k v -> a
#

O(n) Reduce this map by applying a binary operator to all elements, using the given starting value (typically the left-identity of the operator).

valuefoldMapWithKey :: Monoid m => (k -> v -> m) -> HashMap k v -> m
#

O(n) Reduce the map by applying a function to each element and combining the results with a monoid operation.

Filter

4 declarations
valuemapMaybe :: (v1 -> Maybe v2) -> HashMap k v1 -> HashMap k v2
#

O(n) Transform this map by applying a function to every value and retaining only some of them.

valuemapMaybeWithKey :: (k -> v1 -> Maybe v2) -> HashMap k v1 -> HashMap k v2
#

O(n) Transform this map by applying a function to every value and retaining only some of them.

valuefilter :: (v -> Bool) -> HashMap k v -> HashMap k v
#

O(n) Filter this map by retaining only elements which values satisfy a predicate.

Conversions

2 declarations
valuekeys :: HashMap k v -> [k]
#

O(n) Return a list of this map's keys. The list is produced lazily.

valueelems :: HashMap k v -> [v]
#

O(n) Return a list of this map's values. The list is produced lazily.

Lists

valuetoList :: HashMap k v -> [(k, v)]
#

O(n) Return a list of this map's elements. The list is produced lazily. The order of its elements is unspecified, and it may change from version to version of either this package or of hashable.

valuefromList :: Hashable k => [(k, v)] -> HashMap k v
#

O(n \log n) Construct a map with the supplied mappings. If the list contains duplicate mappings, the later mappings take precedence.

valuefromListWith :: Hashable k => (v -> v -> v) -> [(k, v)] -> HashMap k v
#

O(n \log n) Construct a map from a list of elements. Uses the provided function f to merge duplicate entries with (f newVal oldVal).

Examples

Given a list xs, create a map with the number of occurrences of each element in xs:

let xs = ['a', 'b', 'a']
in fromListWith (+) [ (x, 1) | x <- xs ]

= fromList [('a', 2), ('b', 1)]

Given a list of key-value pairs xs :: [(k, v)], group all values by their keys and return a HashMap k [v].

let xs = [('a', 1), ('b', 2), ('a', 3)]
in fromListWith (++) [ (k, [v]) | (k, v) <- xs ]

= fromList [('a', [3, 1]), ('b', [2])]

Note that the lists in the resulting map contain elements in reverse order from their occurrences in the original list.

More generally, duplicate entries are accumulated as follows; this matters when f is not commutative or not associative.

fromListWith f [(k, a), (k, b), (k, c), (k, d)]
= fromList [(k, f d (f c (f b a)))]
valuefromListWithKey
  1. :: Hashable k
  2. => k -> v -> v -> v
  3. -> [(k, v)]
  4. -> HashMap k v
#

O(n \log n) Construct a map from a list of elements. Uses the provided function to merge duplicate entries.

Examples

Given a list of key-value pairs where the keys are of different flavours, e.g:

data Key = Div | Sub

and the values need to be combined differently when there are duplicates, depending on the key:

combine Div = div
combine Sub = (-)

then fromListWithKey can be used as follows:

fromListWithKey combine [(Div, 2), (Div, 6), (Sub, 2), (Sub, 3)]
= fromList [(Div, 3), (Sub, 1)]

More generally, duplicate entries are accumulated as follows;

fromListWith f [(k, a), (k, b), (k, c), (k, d)]
= fromList [(k, f k d (f k c (f k b a)))]

Internals used by the strict version

typetype Hash = Word
#

This type is used to store the hash of a key, as produced with hash.

typetype Shift = Int
#

A Shift value is the offset of the subkey in the hash and corresponds to the level of the tree that we're currently operating at. At the root level the Shift is 0. For the subsequent levels the Shift values are bitsPerSubkey, 2*bitsPerSubkey etc.

Valid values are non-negative and less than bitSize (0 :: Word).

valuehash :: Hashable a => a -> Hash
#

Convenience function. Compute a hash value for the given value.

valuemask :: Hash -> Shift -> Bitmap
#

Given a Hash and a Shift that indicates the level in the tree, compute the bitmap that contains only the index of the hash at this level.

The result can be used for constructing one-element BitmapIndexed nodes or to check whether a BitmapIndexed node may possibly contain the given Hash.

Example1 expression
mask 0b0010_0010 00b0100
valueindex :: Hash -> Shift -> Int
#

Given a Hash and a Shift that indicates the level in the tree, compute the index into a Full node or into the bitmap of a BitmapIndexed node.

Example1 expression
index 0b0010_0010 00b0000_0010
valuebitsPerSubkey :: Int
#

Number of bits that are inspected at each level of the hash tree.

This constant is named t in the original Ideal Hash Trees paper.

Note that this constant is platform-dependent. On 32-bit platforms we use '4', because bitmaps using '2^5' bits turned out to be prone to integer overflow bugs. See #491 for instance.

valuetwo :: Shift -> Hash -> k -> v -> Hash -> HashMap k v -> ST s (HashMap k v)
#

Create a map from two key-value pairs which hashes don't collide. To enhance sharing, the second key-value pair is represented by the hash of its key and a singleton HashMap pairing its key with its value.

Note: to avoid silly thunks, this function must be strict in the key. See issue #232. We don't need to force the HashMap argument because it's already in WHNF (having just been matched) and we just put it directly in an array.

valuelookupRecordCollision :: Eq k => Hash -> k -> HashMap k v -> LookupRes v
#

Internal helper for lookup. This version takes the precomputed hash so that functions that make multiple calls to lookup and related functions (insert, delete) only need to calculate the hash once.

It is used by alterF so that hash computation and key comparison only needs to be performed once. With this information you can use the more optimized versions of insert (insertNewKey, insertKeyExists) and delete (deleteKeyExists)

Outcomes: Key not in map => Absent Key in map, no collision => Present v (-1) Key in map, collision => Present v position

datadata LookupRes a
#

The result of a lookup, keeping track of if a hash collision occurred. If a collision did not occur then it will have the Int value (-1).

Constructors

valuelookup' :: Eq k => Hash -> k -> HashMap k v -> Maybe v
#

lookup' is a version of lookup that takes the hash separately. It is used to implement alterF.

valueinsertNewKey :: Hash -> k -> v -> HashMap k v -> HashMap k v
#

Insert optimized for the case when we know the key is not in the map.

It is only valid to call this when the key does not exist in the map.

We can skip: - the key equality check on a Leaf - check for its existence in the array for a hash collision

valueinsertKeyExists :: Int -> Hash -> k -> v -> HashMap k v -> HashMap k v
#

Insert optimized for the case when we know the key is in the map.

It is only valid to call this when the key exists in the map and you know the hash collision position if there was one. This information can be obtained from lookupRecordCollision. If there is no collision, pass (-1) as collPos (first argument).

valuedeleteKeyExists :: Int -> Hash -> k -> HashMap k v -> HashMap k v
#

Delete optimized for the case when we know the key is in the map.

It is only valid to call this when the key exists in the map and you know the hash collision position if there was one. This information can be obtained from lookupRecordCollision. If there is no collision, pass (-1) as collPos.

valueinsertModifying
  1. :: Hashable k
  2. => v
  3. -> v -> (# v #)
  4. -> k
  5. -> HashMap k v
  6. -> HashMap k v
#

insertModifying is a lot like insertWith; we use it to implement alterF. It takes a value to insert when the key is absent and a function to apply to calculate a new value when the key is present. Thanks to the unboxed unary tuple, we avoid introducing any unnecessary thunks in the tree.

valueptrEq :: a -> a -> Bool
#

Check if two the two arguments are the same value. N.B. This function might give false negatives (due to GC moving objects.)