A lens library for python that enables immutable manipulation of deeply nested data structures
npx @tessl/cli install tessl/pypi-lenses@1.2.00
# Lenses
1
2
A comprehensive Python lens library that enables immutable manipulation of deeply nested data structures without mutation. Inspired by Haskell lenses but adapted for Python's syntax and conventions, providing a functional programming approach to data transformation through a chainable API.
3
4
## Package Information
5
6
- **Package Name**: lenses
7
- **Language**: Python
8
- **Installation**: `pip install lenses`
9
- **Optional Dependencies**: `pip install pyrsistent` (for enhanced immutable data structures)
10
11
## Core Imports
12
13
```python
14
from lenses import lens, bind
15
```
16
17
For advanced usage:
18
19
```python
20
from lenses import lens, bind, UnboundLens
21
from lenses.maybe import Just, Nothing
22
```
23
24
## Basic Usage
25
26
```python
27
from lenses import lens, bind
28
29
# Basic lens operations on lists
30
data = [1, 2, 3, 4, 5]
31
32
# Get values
33
first_item = lens[0].get()(data) # 1
34
all_items = lens.Each().collect()(data) # [1, 2, 3, 4, 5]
35
36
# Set values (returns new list)
37
new_data = lens[1].set(99)(data) # [1, 99, 3, 4, 5]
38
39
# Modify values with functions
40
incremented = lens.Each().modify(lambda x: x + 1)(data) # [2, 3, 4, 5, 6]
41
42
# Working with dictionaries
43
person = {'name': 'Alice', 'age': 30, 'address': {'city': 'Boston', 'state': 'MA'}}
44
45
# Access nested data
46
city = lens['address']['city'].get()(person) # 'Boston'
47
48
# Update nested data immutably
49
updated_person = lens['address']['city'].set('Cambridge')(person)
50
# {'name': 'Alice', 'age': 30, 'address': {'city': 'Cambridge', 'state': 'MA'}}
51
52
# Using bound lenses
53
bound_lens = bind(person)
54
age = bound_lens['age'].get() # 30
55
older_person = bound_lens['age'].modify(lambda x: x + 1)
56
```
57
58
## Architecture
59
60
Lenses provides a layered architecture for immutable data manipulation:
61
62
- **UI Layer**: `UnboundLens` and `BoundLens` classes providing the main user interface
63
- **Optics System**: Low-level optics (Lens, Prism, Traversal, Isomorphism, etc.) that handle the actual data access patterns
64
- **Type Classes**: Functional programming utilities (monoid, functor, applicative)
65
- **Hooks System**: Extension points for custom data types and collections
66
- **Maybe Type**: Optional value handling inspired by functional programming
67
68
This design enables composition of complex data access patterns while maintaining immutability and type safety.
69
70
## Capabilities
71
72
### Core Lens Operations
73
74
The fundamental lens interface providing get, set, modify operations and lens composition through the `&` operator.
75
76
```python { .api }
77
class UnboundLens:
78
def get(self) -> StateFunction[S, B]: ...
79
def set(self, newvalue: B) -> StateFunction[S, T]: ...
80
def modify(self, func: Callable[[A], B]) -> StateFunction[S, T]: ...
81
def __and__(self, other) -> UnboundLens: ...
82
83
class BoundLens:
84
def get(self) -> B: ...
85
def set(self, newvalue: B) -> T: ...
86
def modify(self, func: Callable[[A], B]) -> T: ...
87
88
def bind(state: S) -> BoundLens[S, S, S, S]: ...
89
```
90
91
[Core Lens Operations](./core-lenses.md)
92
93
### Lens Constructors
94
95
Comprehensive collection of lens constructors for accessing different data structures and implementing various access patterns including containers, objects, traversals, and transformations.
96
97
```python { .api }
98
def Each(self) -> BaseUiLens: ...
99
def GetItem(self, key: Any) -> BaseUiLens: ...
100
def GetAttr(self, name: str) -> BaseUiLens: ...
101
def Filter(self, predicate: Callable[[A], bool]) -> BaseUiLens: ...
102
def Items(self) -> BaseUiLens: ...
103
def Values(self) -> BaseUiLens: ...
104
def Keys(self) -> BaseUiLens: ...
105
def Json(self) -> BaseUiLens: ...
106
```
107
108
[Lens Constructors](./lens-constructors.md)
109
110
### Optics System
111
112
Low-level optics system providing the mathematical foundation with different optic types (Lens, Prism, Traversal, Isomorphism, etc.) that can be composed to create complex data access patterns.
113
114
```python { .api }
115
class Lens: ...
116
class Prism: ...
117
class Traversal: ...
118
class Isomorphism: ...
119
class Fold: ...
120
class Setter: ...
121
```
122
123
[Optics System](./optics.md)
124
125
### Utility Types
126
127
Supporting types including Maybe monad for optional values, type class system for functional programming patterns, and hooks system for extending support to custom data types.
128
129
```python { .api }
130
class Just:
131
def __init__(self, item: A) -> None: ...
132
def map(self, fn: Callable[[A], B]) -> Just[B]: ...
133
def maybe(self, guard: B) -> Union[A, B]: ...
134
135
class Nothing(Just): ...
136
137
def mempty(monoid: Any) -> Any: ...
138
def mappend(monoid: Any, other: Any) -> Any: ...
139
```
140
141
[Utility Types](./utility-types.md)
142
143
## Global Variables
144
145
```python { .api }
146
lens: UnboundLens # Main lens object, entry point to the library
147
```
148
149
## Types
150
151
```python { .api }
152
from typing import TypeVar, Callable, List, Iterable, Union, Optional, Any
153
154
S = TypeVar("S") # Source type
155
T = TypeVar("T") # Target type
156
A = TypeVar("A") # Focus input type
157
B = TypeVar("B") # Focus output type
158
159
StateFunction[S, T] = Callable[[S], T]
160
```