Skip to content

Commit 594a305

Browse files
authored
Document that HashMaps have a canonical form (#593)
Closes #450. Assisted-by: Claude Fable 5
1 parent c801302 commit 594a305

1 file changed

Lines changed: 32 additions & 0 deletions

File tree

Data/HashMap/Internal.hs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,38 @@ data HashMap k v
254254
-- * No two keys stored in a 'Collision' can be equal according to their
255255
-- 'Eq' instance. (INV10)
256256

257+
{-
258+
Note [Canonical form]
259+
~~~~~~~~~~~~~~~~~~~~~
260+
261+
The invariants above imply that HashMaps have a canonical form: two
262+
HashMaps that contain the same key-value pairs have the same tree
263+
structure, modulo the order of keys within a Collision node -- regardless
264+
of the order in which they were constructed. This is because each key's
265+
hash fully determines the path to its leaf, while the remaining
266+
invariants, in particular INV1, INV3, INV5, INV8 and INV9, rule out
267+
alternative encodings of the same sub-tree (e.g. a redundant
268+
BitmapIndexed node wrapping a single Leaf, a BitmapIndexed node that
269+
could be a Full node, or a single-entry Collision node that could be a
270+
Leaf).
271+
272+
Several functions rely on this, in two ways:
273+
274+
* equal1 and equalKeys compare two trees structurally, node by node.
275+
Canonical form makes this complete: maps with equal contents have
276+
identical structure, except within Collision nodes, which these
277+
functions compare as unordered collections.
278+
279+
* equal2, cmp, equalKeys1 and the Hashable instances flatten a tree with
280+
leavesAndCollisions. Canonical form guarantees that maps with equal
281+
contents produce the same sequence of leaves, again modulo the order
282+
within Collision nodes, which these functions handle
283+
order-insensitively.
284+
285+
Without a canonical form these functions could give inconsistent results
286+
for maps with equal contents.
287+
-}
288+
257289
type role HashMap nominal representational
258290

259291
-- | @since 0.2.17.0

0 commit comments

Comments
 (0)