Persistent
Persistent data structures with structural sharing for efficient immutable updates. Based on Clojure-style persistent collections with O(log32 n) operations.
When you "modify" a persistent collection, the new version shares structure with the old version, making updates memory-efficient and enabling safe concurrent access without locks.
PVec (Persistent Vector)
Indexed collection with fast random access and updates at the end.
vec = PVec.empty |> PVec.append 1 |> PVec.append 2 |> PVec.append 3
PVec.to-list vec # => [1, 2, 3]
PVec.get vec 1 # => Some 2
PVec.get vec 99 # => None
vec2 = PVec.set vec 1 42
PVec.to-list vec2 # => [1, 42, 3]
PVec.to-list vec # => [1, 2, 3] (unchanged)
PMap (Persistent HashMap)
Hash array mapped trie (HAMT) for efficient key-value storage.
m = PMap.empty
|> PMap.insert "name" "Alice"
|> PMap.insert "age" 30
PMap.get m "name" # => Some "Alice"
update-or provides default if key missing.# Increment counter, starting at 0 if missing
m2 = PMap.update-or m "count" 0 (fn(n) => n + 1)
merge-with uses function to resolve conflicts.PSet (Persistent HashSet)
Hash set with efficient membership testing and set operations.
s = PSet.empty |> PSet.insert 1 |> PSet.insert 2 |> PSet.insert 3
PSet.member? s 2 # => true
a = PSet.from-list [1, 2, 3]
b = PSet.from-list [2, 3, 4]
PSet.to-list (PSet.intersection a b) # => [2, 3]
Transients
For building collections with many mutations, transients provide efficient mutable operations before converting back to persistent.
# Build vector efficiently with transient
vec = PVec.empty
|> PVec.transient
|> PVec.append! 1
|> PVec.append! 2
|> PVec.append! 3
|> PVec.persistent