🗄️ Hash Map

Persistent functional hash map with separate chaining

Overview

An immutable hash map using separate chaining with resizable bucket arrays. All operations return new maps — old versions remain valid (structural sharing via Array.copy). Automatically resizes when load factor exceeds 0.75.

Concepts Demonstrated

Key Functions

FunctionDescription
createCreate empty map with optional capacity
insertAdd/update a key-value pair
findLook up by key (returns option)
removeRemove a key
memCheck membership
fold / iterTraverse all bindings
map / mapiTransform values (with or without keys)
filterKeep bindings matching a predicate
mergeCombine two maps with a merge function
equalStructural equality comparison
of_list / to_listConvert to/from association lists

Usage

open FunMap

let m = empty
  |> insert "alice" 30
  |> insert "bob" 25
  |> insert "charlie" 35

let _ = find "alice" m         (* → Some 30 *)
let _ = mem "dave" m           (* → false *)
let _ = size m                 (* → 3 *)

(* Immutable: original 'm' unchanged after operations *)
let m2 = remove "bob" m       (* m still has 3 entries *)

Resizing Strategy

The map starts with 16 buckets and doubles capacity when the load factor (size/capacity) exceeds 0.75. Resizing rehashes all entries into the new bucket array. This amortizes to O(1) per insertion.

let should_resize m =
  m.size > (m.capacity * 3 / 4)