0
# Core Persistent Collections
1
2
Immutable alternatives to Python's built-in collections that use structural sharing for memory efficiency. All collections provide O(log32 n) performance for most operations and return new instances rather than modifying in-place.
3
4
## Capabilities
5
6
### PMap - Persistent Dictionary
7
8
Immutable mapping similar to Python's dict with efficient updates and lookups. Supports all standard mapping operations plus additional persistent-specific methods.
9
10
```python { .api }
11
def pmap(initial: Union[Mapping[KT, VT], Iterable[Tuple[KT, VT]]] = {}, pre_size: int = 0) -> PMap[KT, VT]:
12
"""
13
Create a persistent map from a mapping or iterable of key-value pairs.
14
15
Parameters:
16
- initial: Initial mapping or iterable of (key, value) pairs
17
- pre_size: Expected size for optimization (optional)
18
19
Returns:
20
PMap instance
21
"""
22
23
def m(**kwargs) -> PMap[str, Any]:
24
"""
25
Create a persistent map from keyword arguments.
26
27
Returns:
28
PMap instance with kwargs as key-value pairs
29
"""
30
31
class PMap:
32
def get(self, key, default=None):
33
"""Get value for key, return default if key not found."""
34
35
def set(self, key, value) -> 'PMap':
36
"""Return new PMap with key set to value."""
37
38
def remove(self, key) -> 'PMap':
39
"""Return new PMap without key. Raises KeyError if key missing."""
40
41
def discard(self, key) -> 'PMap':
42
"""Return new PMap without key. Silent if key missing."""
43
44
def update(self, *mappings) -> 'PMap':
45
"""Return new PMap with items from other mappings."""
46
47
def update_with(self, update_fn, *mappings) -> 'PMap':
48
"""Return new PMap updated with merge function for conflicts."""
49
50
def evolver(self) -> 'PMapEvolver':
51
"""Return mutable-like interface for efficient batch updates."""
52
53
def transform(self, *transformations) -> 'PMap':
54
"""Apply path-based transformations to nested structure."""
55
56
def keys(self) -> 'PSet':
57
"""Return PSet of keys."""
58
59
def values(self) -> 'PMapValues':
60
"""Return view of values."""
61
62
def items(self) -> 'PMapItems':
63
"""Return view of key-value pairs."""
64
65
def copy(self) -> 'PMap':
66
"""Return self (immutable, so copy is identity)."""
67
```
68
69
### PVector - Persistent List
70
71
Immutable sequence similar to Python's list with efficient append, random access, and slicing operations.
72
73
```python { .api }
74
def pvector(iterable: Iterable = ()) -> PVector:
75
"""
76
Create a persistent vector from an iterable.
77
78
Parameters:
79
- iterable: Items to include in vector
80
81
Returns:
82
PVector instance
83
"""
84
85
def v(*elements) -> PVector:
86
"""
87
Create a persistent vector from arguments.
88
89
Returns:
90
PVector containing the arguments as elements
91
"""
92
93
class PVector:
94
def append(self, element) -> 'PVector':
95
"""Return new PVector with element appended."""
96
97
def extend(self, iterable) -> 'PVector':
98
"""Return new PVector with elements from iterable appended."""
99
100
def set(self, index: int, value) -> 'PVector':
101
"""Return new PVector with element at index replaced."""
102
103
def mset(self, *args) -> 'PVector':
104
"""Multi-set: mset(index1, val1, index2, val2, ...)"""
105
106
def delete(self, index: int, stop: int = None) -> 'PVector':
107
"""Return new PVector with elements removed."""
108
109
def remove(self, value) -> 'PVector':
110
"""Return new PVector with first occurrence of value removed."""
111
112
def evolver(self) -> 'PVectorEvolver':
113
"""Return mutable-like interface for efficient batch updates."""
114
115
def transform(self, *transformations) -> 'PVector':
116
"""Apply path-based transformations to nested structure."""
117
118
def tolist(self) -> list:
119
"""Convert to Python list."""
120
121
def index(self, value, start: int = 0, stop: int = None) -> int:
122
"""Return index of first occurrence of value."""
123
124
def count(self, value) -> int:
125
"""Return number of occurrences of value."""
126
```
127
128
### PSet - Persistent Set
129
130
Immutable set with efficient membership testing, set operations, and updates.
131
132
```python { .api }
133
def pset(iterable: Iterable = (), pre_size: int = 8) -> PSet:
134
"""
135
Create a persistent set from an iterable.
136
137
Parameters:
138
- iterable: Items to include in set
139
- pre_size: Expected size for optimization
140
141
Returns:
142
PSet instance
143
"""
144
145
def s(*elements) -> PSet:
146
"""
147
Create a persistent set from arguments.
148
149
Returns:
150
PSet containing the arguments as elements
151
"""
152
153
class PSet:
154
def add(self, element) -> 'PSet':
155
"""Return new PSet with element added."""
156
157
def update(self, iterable) -> 'PSet':
158
"""Return new PSet with elements from iterable added."""
159
160
def remove(self, element) -> 'PSet':
161
"""Return new PSet without element. Raises KeyError if missing."""
162
163
def discard(self, element) -> 'PSet':
164
"""Return new PSet without element. Silent if missing."""
165
166
def evolver(self) -> 'PSetEvolver':
167
"""Return mutable-like interface for efficient batch updates."""
168
169
def union(self, *others) -> 'PSet':
170
"""Return new PSet with elements from all sets."""
171
172
def intersection(self, *others) -> 'PSet':
173
"""Return new PSet with elements common to all sets."""
174
175
def difference(self, *others) -> 'PSet':
176
"""Return new PSet with elements not in other sets."""
177
178
def symmetric_difference(self, other) -> 'PSet':
179
"""Return new PSet with elements in either set but not both."""
180
181
def issubset(self, other) -> bool:
182
"""Test whether every element is in other."""
183
184
def issuperset(self, other) -> bool:
185
"""Test whether every element in other is in this set."""
186
187
def isdisjoint(self, other) -> bool:
188
"""Return True if sets have no elements in common."""
189
190
def copy(self) -> 'PSet':
191
"""Return self (immutable, so copy is identity)."""
192
```
193
194
### PBag - Persistent Multiset
195
196
Immutable multiset (bag) that allows duplicate elements and tracks element counts.
197
198
```python { .api }
199
def pbag(elements: Iterable) -> PBag:
200
"""
201
Create a persistent bag from an iterable.
202
203
Parameters:
204
- elements: Items to include (duplicates allowed)
205
206
Returns:
207
PBag instance
208
"""
209
210
def b(*elements) -> PBag:
211
"""
212
Create a persistent bag from arguments.
213
214
Returns:
215
PBag containing the arguments as elements
216
"""
217
218
class PBag:
219
def add(self, element) -> 'PBag':
220
"""Return new PBag with element added (increments count)."""
221
222
def remove(self, element) -> 'PBag':
223
"""Return new PBag with one occurrence of element removed."""
224
225
def count(self, element) -> int:
226
"""Return number of occurrences of element."""
227
228
def update(self, iterable) -> 'PBag':
229
"""Return new PBag with elements from iterable added."""
230
```
231
232
### PList - Persistent Linked List
233
234
Immutable singly-linked list optimized for prepending operations and functional programming patterns.
235
236
```python { .api }
237
def plist(iterable: Iterable = (), reverse: bool = False) -> PList:
238
"""
239
Create a persistent linked list from an iterable.
240
241
Parameters:
242
- iterable: Items to include
243
- reverse: If True, reverse the order
244
245
Returns:
246
PList instance
247
"""
248
249
def l(*elements) -> PList:
250
"""
251
Create a persistent linked list from arguments.
252
253
Returns:
254
PList containing the arguments as elements
255
"""
256
257
class PList:
258
def cons(self, element) -> 'PList':
259
"""Return new PList with element prepended."""
260
261
def mcons(self, iterable) -> 'PList':
262
"""Return new PList with elements from iterable prepended."""
263
264
@property
265
def first(self):
266
"""First element of the list."""
267
268
@property
269
def rest(self) -> 'PList':
270
"""PList of remaining elements after first."""
271
272
def reverse(self) -> 'PList':
273
"""Return new PList in reverse order."""
274
275
def remove(self, element) -> 'PList':
276
"""Return new PList with first occurrence of element removed."""
277
278
def split(self, index: int) -> tuple:
279
"""Return tuple of (left, right) PLists split at index."""
280
```
281
282
### PDeque - Persistent Double-Ended Queue
283
284
Immutable double-ended queue with efficient operations at both ends and optional maximum length.
285
286
```python { .api }
287
def pdeque(iterable: Iterable = None, maxlen: int = None) -> PDeque:
288
"""
289
Create a persistent deque from an iterable.
290
291
Parameters:
292
- iterable: Items to include
293
- maxlen: Maximum length (None for unlimited)
294
295
Returns:
296
PDeque instance
297
"""
298
299
def dq(*elements) -> PDeque:
300
"""
301
Create a persistent deque from arguments.
302
303
Returns:
304
PDeque containing the arguments as elements
305
"""
306
307
class PDeque:
308
def append(self, element) -> 'PDeque':
309
"""Return new PDeque with element appended to right."""
310
311
def appendleft(self, element) -> 'PDeque':
312
"""Return new PDeque with element prepended to left."""
313
314
def extend(self, iterable) -> 'PDeque':
315
"""Return new PDeque with elements from iterable appended."""
316
317
def extendleft(self, iterable) -> 'PDeque':
318
"""Return new PDeque with elements from iterable prepended."""
319
320
def pop(self, count: int = 1) -> 'PDeque':
321
"""Return new PDeque with count elements removed from right."""
322
323
def popleft(self, count: int = 1) -> 'PDeque':
324
"""Return new PDeque with count elements removed from left."""
325
326
@property
327
def left(self):
328
"""Leftmost element."""
329
330
@property
331
def right(self):
332
"""Rightmost element."""
333
334
@property
335
def maxlen(self) -> int:
336
"""Maximum length (None if unlimited)."""
337
338
def rotate(self, steps: int) -> 'PDeque':
339
"""Return new PDeque rotated by steps."""
340
341
def reverse(self) -> 'PDeque':
342
"""Return new PDeque in reverse order."""
343
344
def remove(self, element) -> 'PDeque':
345
"""Return new PDeque with first occurrence of element removed."""
346
```
347
348
## Factory Function Shortcuts
349
350
Convenient single-character aliases for creating collections:
351
352
```python { .api }
353
def m(**kwargs) -> PMap[str, Any]: ... # pmap from keyword arguments
354
def v(*elements: T) -> PVector[T]: ... # pvector from arguments
355
def s(*elements: T) -> PSet[T]: ... # pset from arguments
356
def b(*elements: T) -> PBag[T]: ... # pbag from arguments
357
def l(*elements: T) -> PList[T]: ... # plist from arguments
358
def dq(*elements: T) -> PDeque[T]: ... # pdeque from arguments
359
```
360
361
## Evolver Interfaces
362
363
All main collections provide `.evolver()` methods returning mutable-like interfaces for efficient batch updates:
364
365
```python { .api }
366
class PMapEvolver:
367
def __setitem__(self, key, value) -> None: ...
368
def __delitem__(self, key) -> None: ...
369
def set(self, key, value) -> 'PMapEvolver': ...
370
def remove(self, key) -> 'PMapEvolver': ...
371
def is_dirty(self) -> bool: ...
372
def persistent(self) -> PMap: ...
373
374
class PVectorEvolver:
375
def __setitem__(self, index: int, value) -> None: ...
376
def __delitem__(self, index: int) -> None: ...
377
def append(self, value) -> 'PVectorEvolver': ...
378
def extend(self, iterable) -> 'PVectorEvolver': ...
379
def set(self, index: int, value) -> 'PVectorEvolver': ...
380
def delete(self, value) -> 'PVectorEvolver': ...
381
def is_dirty(self) -> bool: ...
382
def persistent(self) -> PVector: ...
383
384
class PSetEvolver:
385
def add(self, element) -> 'PSetEvolver': ...
386
def remove(self, element) -> 'PSetEvolver': ...
387
def is_dirty(self) -> bool: ...
388
def persistent(self) -> PSet: ...
389
```
390
391
## Usage Examples
392
393
```python
394
# Efficient batch updates using evolvers
395
pm = pmap({'a': 1, 'b': 2})
396
evolver = pm.evolver()
397
evolver['c'] = 3
398
evolver['d'] = 4
399
del evolver['a']
400
new_pm = evolver.persistent() # Get immutable result
401
402
# Chaining operations
403
pv = pvector([1, 2, 3])
404
result = pv.append(4).extend([5, 6]).set(0, 0) # pvector([0, 2, 3, 4, 5, 6])
405
406
# Set operations
407
ps1 = pset([1, 2, 3])
408
ps2 = pset([3, 4, 5])
409
union = ps1.union(ps2) # pset([1, 2, 3, 4, 5])
410
intersection = ps1 & ps2 # pset([3]) - using operator
411
```