# Core Persistent Collections

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.

## Capabilities

### PMap - Persistent Dictionary

Immutable mapping similar to Python's dict with efficient updates and lookups. Supports all standard mapping operations plus additional persistent-specific methods.

```python { .api }
def pmap(initial: Union[Mapping[KT, VT], Iterable[Tuple[KT, VT]]] = {}, pre_size: int = 0) -> PMap[KT, VT]:
    """
    Create a persistent map from a mapping or iterable of key-value pairs.
    
    Parameters:
    - initial: Initial mapping or iterable of (key, value) pairs
    - pre_size: Expected size for optimization (optional)
    
    Returns:
    PMap instance
    """

def m(**kwargs) -> PMap[str, Any]:
    """
    Create a persistent map from keyword arguments.
    
    Returns:
    PMap instance with kwargs as key-value pairs
    """

class PMap:
    def get(self, key, default=None):
        """Get value for key, return default if key not found."""
    
    def set(self, key, value) -> 'PMap':
        """Return new PMap with key set to value."""
    
    def remove(self, key) -> 'PMap':
        """Return new PMap without key. Raises KeyError if key missing."""
    
    def discard(self, key) -> 'PMap':
        """Return new PMap without key. Silent if key missing."""
    
    def update(self, *mappings) -> 'PMap':
        """Return new PMap with items from other mappings."""
    
    def update_with(self, update_fn, *mappings) -> 'PMap':
        """Return new PMap updated with merge function for conflicts."""
    
    def evolver(self) -> 'PMapEvolver':
        """Return mutable-like interface for efficient batch updates."""
    
    def transform(self, *transformations) -> 'PMap':
        """Apply path-based transformations to nested structure."""
    
    def keys(self) -> 'PSet':
        """Return PSet of keys."""
    
    def values(self) -> 'PMapValues':
        """Return view of values."""
    
    def items(self) -> 'PMapItems':
        """Return view of key-value pairs."""
    
    def copy(self) -> 'PMap':
        """Return self (immutable, so copy is identity)."""
```

### PVector - Persistent List

Immutable sequence similar to Python's list with efficient append, random access, and slicing operations.

```python { .api }
def pvector(iterable: Iterable = ()) -> PVector:
    """
    Create a persistent vector from an iterable.
    
    Parameters:
    - iterable: Items to include in vector
    
    Returns:
    PVector instance
    """

def v(*elements) -> PVector:
    """
    Create a persistent vector from arguments.
    
    Returns:
    PVector containing the arguments as elements
    """

class PVector:
    def append(self, element) -> 'PVector':
        """Return new PVector with element appended."""
    
    def extend(self, iterable) -> 'PVector':
        """Return new PVector with elements from iterable appended."""
    
    def set(self, index: int, value) -> 'PVector':
        """Return new PVector with element at index replaced."""
    
    def mset(self, *args) -> 'PVector':
        """Multi-set: mset(index1, val1, index2, val2, ...)"""
    
    def delete(self, index: int, stop: int = None) -> 'PVector':
        """Return new PVector with elements removed."""
    
    def remove(self, value) -> 'PVector':
        """Return new PVector with first occurrence of value removed."""
    
    def evolver(self) -> 'PVectorEvolver':
        """Return mutable-like interface for efficient batch updates."""
    
    def transform(self, *transformations) -> 'PVector':
        """Apply path-based transformations to nested structure."""
    
    def tolist(self) -> list:
        """Convert to Python list."""
    
    def index(self, value, start: int = 0, stop: int = None) -> int:
        """Return index of first occurrence of value."""
    
    def count(self, value) -> int:
        """Return number of occurrences of value."""
```

### PSet - Persistent Set

Immutable set with efficient membership testing, set operations, and updates.

```python { .api }
def pset(iterable: Iterable = (), pre_size: int = 8) -> PSet:
    """
    Create a persistent set from an iterable.
    
    Parameters:
    - iterable: Items to include in set
    - pre_size: Expected size for optimization
    
    Returns:
    PSet instance
    """

def s(*elements) -> PSet:
    """
    Create a persistent set from arguments.
    
    Returns:
    PSet containing the arguments as elements
    """

class PSet:
    def add(self, element) -> 'PSet':
        """Return new PSet with element added."""
    
    def update(self, iterable) -> 'PSet':
        """Return new PSet with elements from iterable added."""
    
    def remove(self, element) -> 'PSet':
        """Return new PSet without element. Raises KeyError if missing."""
    
    def discard(self, element) -> 'PSet':
        """Return new PSet without element. Silent if missing."""
    
    def evolver(self) -> 'PSetEvolver':
        """Return mutable-like interface for efficient batch updates."""
    
    def union(self, *others) -> 'PSet':
        """Return new PSet with elements from all sets."""
    
    def intersection(self, *others) -> 'PSet':
        """Return new PSet with elements common to all sets."""
    
    def difference(self, *others) -> 'PSet':
        """Return new PSet with elements not in other sets."""
    
    def symmetric_difference(self, other) -> 'PSet':
        """Return new PSet with elements in either set but not both."""
    
    def issubset(self, other) -> bool:
        """Test whether every element is in other."""
    
    def issuperset(self, other) -> bool:
        """Test whether every element in other is in this set."""
    
    def isdisjoint(self, other) -> bool:
        """Return True if sets have no elements in common."""
    
    def copy(self) -> 'PSet':
        """Return self (immutable, so copy is identity)."""
```

### PBag - Persistent Multiset

Immutable multiset (bag) that allows duplicate elements and tracks element counts.

```python { .api }
def pbag(elements: Iterable) -> PBag:
    """
    Create a persistent bag from an iterable.
    
    Parameters:
    - elements: Items to include (duplicates allowed)
    
    Returns:
    PBag instance
    """

def b(*elements) -> PBag:
    """
    Create a persistent bag from arguments.
    
    Returns:
    PBag containing the arguments as elements
    """

class PBag:
    def add(self, element) -> 'PBag':
        """Return new PBag with element added (increments count)."""
    
    def remove(self, element) -> 'PBag':
        """Return new PBag with one occurrence of element removed."""
    
    def count(self, element) -> int:
        """Return number of occurrences of element."""
    
    def update(self, iterable) -> 'PBag':
        """Return new PBag with elements from iterable added."""
```

### PList - Persistent Linked List

Immutable singly-linked list optimized for prepending operations and functional programming patterns.

```python { .api }
def plist(iterable: Iterable = (), reverse: bool = False) -> PList:
    """
    Create a persistent linked list from an iterable.
    
    Parameters:
    - iterable: Items to include
    - reverse: If True, reverse the order
    
    Returns:
    PList instance
    """

def l(*elements) -> PList:
    """
    Create a persistent linked list from arguments.
    
    Returns:
    PList containing the arguments as elements
    """

class PList:
    def cons(self, element) -> 'PList':
        """Return new PList with element prepended."""
    
    def mcons(self, iterable) -> 'PList':
        """Return new PList with elements from iterable prepended."""
    
    @property
    def first(self):
        """First element of the list."""
    
    @property
    def rest(self) -> 'PList':
        """PList of remaining elements after first."""
    
    def reverse(self) -> 'PList':
        """Return new PList in reverse order."""
    
    def remove(self, element) -> 'PList':
        """Return new PList with first occurrence of element removed."""
    
    def split(self, index: int) -> tuple:
        """Return tuple of (left, right) PLists split at index."""
```

### PDeque - Persistent Double-Ended Queue

Immutable double-ended queue with efficient operations at both ends and optional maximum length.

```python { .api }
def pdeque(iterable: Iterable = None, maxlen: int = None) -> PDeque:
    """
    Create a persistent deque from an iterable.
    
    Parameters:
    - iterable: Items to include
    - maxlen: Maximum length (None for unlimited)
    
    Returns:
    PDeque instance
    """

def dq(*elements) -> PDeque:
    """
    Create a persistent deque from arguments.
    
    Returns:
    PDeque containing the arguments as elements
    """

class PDeque:
    def append(self, element) -> 'PDeque':
        """Return new PDeque with element appended to right."""
    
    def appendleft(self, element) -> 'PDeque':
        """Return new PDeque with element prepended to left."""
    
    def extend(self, iterable) -> 'PDeque':
        """Return new PDeque with elements from iterable appended."""
    
    def extendleft(self, iterable) -> 'PDeque':
        """Return new PDeque with elements from iterable prepended."""
    
    def pop(self, count: int = 1) -> 'PDeque':
        """Return new PDeque with count elements removed from right."""
    
    def popleft(self, count: int = 1) -> 'PDeque':
        """Return new PDeque with count elements removed from left."""
    
    @property
    def left(self):
        """Leftmost element."""
    
    @property
    def right(self):
        """Rightmost element."""
    
    @property
    def maxlen(self) -> int:
        """Maximum length (None if unlimited)."""
    
    def rotate(self, steps: int) -> 'PDeque':
        """Return new PDeque rotated by steps."""
    
    def reverse(self) -> 'PDeque':
        """Return new PDeque in reverse order."""
    
    def remove(self, element) -> 'PDeque':
        """Return new PDeque with first occurrence of element removed."""
```

## Factory Function Shortcuts

Convenient single-character aliases for creating collections:

```python { .api }
def m(**kwargs) -> PMap[str, Any]: ...         # pmap from keyword arguments
def v(*elements: T) -> PVector[T]: ...         # pvector from arguments  
def s(*elements: T) -> PSet[T]: ...            # pset from arguments
def b(*elements: T) -> PBag[T]: ...            # pbag from arguments
def l(*elements: T) -> PList[T]: ...           # plist from arguments
def dq(*elements: T) -> PDeque[T]: ...         # pdeque from arguments
```

## Evolver Interfaces

All main collections provide `.evolver()` methods returning mutable-like interfaces for efficient batch updates:

```python { .api }
class PMapEvolver:
    def __setitem__(self, key, value) -> None: ...
    def __delitem__(self, key) -> None: ...
    def set(self, key, value) -> 'PMapEvolver': ...
    def remove(self, key) -> 'PMapEvolver': ...
    def is_dirty(self) -> bool: ...
    def persistent(self) -> PMap: ...

class PVectorEvolver:
    def __setitem__(self, index: int, value) -> None: ...
    def __delitem__(self, index: int) -> None: ...
    def append(self, value) -> 'PVectorEvolver': ...
    def extend(self, iterable) -> 'PVectorEvolver': ...
    def set(self, index: int, value) -> 'PVectorEvolver': ...
    def delete(self, value) -> 'PVectorEvolver': ...
    def is_dirty(self) -> bool: ...
    def persistent(self) -> PVector: ...

class PSetEvolver:
    def add(self, element) -> 'PSetEvolver': ...
    def remove(self, element) -> 'PSetEvolver': ...
    def is_dirty(self) -> bool: ...
    def persistent(self) -> PSet: ...
```

## Usage Examples

```python
# Efficient batch updates using evolvers
pm = pmap({'a': 1, 'b': 2})
evolver = pm.evolver()
evolver['c'] = 3
evolver['d'] = 4
del evolver['a']
new_pm = evolver.persistent()  # Get immutable result

# Chaining operations
pv = pvector([1, 2, 3])
result = pv.append(4).extend([5, 6]).set(0, 0)  # pvector([0, 2, 3, 4, 5, 6])

# Set operations
ps1 = pset([1, 2, 3])
ps2 = pset([3, 4, 5])
union = ps1.union(ps2)        # pset([1, 2, 3, 4, 5])
intersection = ps1 & ps2      # pset([3]) - using operator
```