0
# Core Lens Operations
1
2
The fundamental lens interface providing get, set, modify operations and lens composition. These core operations form the foundation of all lens-based data manipulation in the library.
3
4
## Capabilities
5
6
### UnboundLens
7
8
The main lens class that provides composable data access patterns without being bound to specific state. All lens constructors return UnboundLens instances.
9
10
```python { .api }
11
class UnboundLens:
12
def __init__(self, optic): ...
13
14
def get(self) -> StateFunction[S, B]:
15
"""Get the first value focused by the lens."""
16
17
def collect(self) -> StateFunction[S, List[B]]:
18
"""Get multiple values focused by the lens as a list."""
19
20
def get_monoid(self) -> StateFunction[S, B]:
21
"""Get values focused by the lens, merging them as a monoid."""
22
23
def set(self, newvalue: B) -> StateFunction[S, T]:
24
"""Set the focus to newvalue."""
25
26
def set_many(self, new_values: Iterable[B]) -> StateFunction[S, T]:
27
"""Set many foci to values from new_values iterable."""
28
29
def modify(self, func: Callable[[A], B]) -> StateFunction[S, T]:
30
"""Apply a function to the focus."""
31
32
def construct(self, focus: A) -> S:
33
"""Construct a state given a focus."""
34
35
def flip(self) -> UnboundLens[A, B, S, T]:
36
"""Flips the direction of the lens (requires isomorphisms)."""
37
38
def kind(self) -> str:
39
"""Returns the 'kind' of the lens."""
40
41
def __and__(self, other) -> UnboundLens:
42
"""Compose this lens with another lens or apply function to focus."""
43
44
def add_lens(self, other) -> UnboundLens:
45
"""Alias for __and__."""
46
```
47
48
#### Usage Examples
49
50
```python
51
from lenses import lens
52
53
# Basic getting
54
data = [1, 2, 3]
55
first = lens[0].get()(data) # 1
56
57
# Setting creates new data structures
58
new_data = lens[1].set(99)(data) # [1, 99, 3]
59
60
# Modifying with functions
61
doubled = lens.Each().modify(lambda x: x * 2)(data) # [2, 4, 6]
62
63
# Lens composition with &
64
nested = [[1, 2], [3, 4], [5, 6]]
65
first_of_each = lens.Each()[0].collect()(nested) # [1, 3, 5]
66
67
# Function application with &
68
add_ten = lens[0] & (lambda x: x + 10)
69
result = add_ten(data) # [11, 2, 3]
70
```
71
72
### BoundLens
73
74
A lens that has been bound to specific state, providing direct access without needing to pass state as a parameter.
75
76
```python { .api }
77
class BoundLens:
78
def __init__(self, state: S, optic) -> None: ...
79
80
def get(self) -> B:
81
"""Get the first value focused by the lens."""
82
83
def collect(self) -> List[B]:
84
"""Get multiple values focused by the lens as a list."""
85
86
def get_monoid(self) -> B:
87
"""Get values focused by the lens, merging them as a monoid."""
88
89
def set(self, newvalue: B) -> T:
90
"""Set the focus to newvalue."""
91
92
def set_many(self, new_values: Iterable[B]) -> T:
93
"""Set many foci to values from new_values iterable."""
94
95
def modify(self, func: Callable[[A], B]) -> T:
96
"""Apply a function to the focus."""
97
98
def kind(self) -> str:
99
"""Returns the 'kind' of the lens."""
100
101
def __and__(self, other) -> BoundLens:
102
"""Compose this lens with another lens or apply function to focus."""
103
104
def add_lens(self, other) -> BoundLens:
105
"""Alias for __and__."""
106
```
107
108
#### Usage Examples
109
110
```python
111
from lenses import bind
112
113
# Create bound lens
114
data = {"users": [{"name": "Alice", "age": 25}, {"name": "Bob", "age": 30}]}
115
bound = bind(data)
116
117
# Direct operations without passing state
118
first_user_name = bound["users"][0]["name"].get() # "Alice"
119
updated_data = bound["users"][0]["age"].set(26)
120
121
# Composition works the same
122
all_ages = bound["users"].Each()["age"].collect() # [25, 30]
123
```
124
125
### StateFunction
126
127
A wrapper for functions that operate on state, returned by UnboundLens operations.
128
129
```python { .api }
130
class StateFunction:
131
def __init__(self, func: Callable[[S], T]): ...
132
def __call__(self, state: S) -> T: ...
133
```
134
135
#### Usage Examples
136
137
```python
138
from lenses import lens
139
140
# Get operations return StateFunctions
141
getter = lens[0].get() # StateFunction
142
value = getter([1, 2, 3]) # 1
143
144
# Set operations return StateFunctions
145
setter = lens[1].set(99) # StateFunction
146
new_list = setter([1, 2, 3]) # [1, 99, 3]
147
```
148
149
### Bind Function
150
151
Creates a BoundLens from state, providing an alternative entry point to the lens system.
152
153
```python { .api }
154
def bind(state: S) -> BoundLens[S, S, S, S]:
155
"""Returns a simple BoundLens object bound to state."""
156
```
157
158
#### Usage Examples
159
160
```python
161
from lenses import bind
162
163
# Create bound lens for immediate operations
164
data = [1, 2, 3, 4, 5]
165
bound_data = bind(data)
166
167
# Perform operations directly
168
first = bound_data[0].get() # 1
169
modified = bound_data.Each().modify(lambda x: x + 1) # [2, 3, 4, 5, 6]
170
171
# Useful for method chaining
172
result = (bind({"a": [1, 2, 3]})
173
["a"]
174
.Each()
175
.modify(lambda x: x * 2)
176
.collect()) # [2, 4, 6] from modified state
177
```
178
179
### Lens Composition
180
181
Lenses can be composed using the `&` operator to create complex data access patterns.
182
183
```python { .api }
184
# Composition operator
185
lens_a & lens_b # Compose two lenses
186
lens_a & function # Apply function to lens focus
187
```
188
189
#### Composition Examples
190
191
```python
192
from lenses import lens
193
194
# Nested data access
195
data = [{"values": [1, 2, 3]}, {"values": [4, 5, 6]}]
196
197
# Compose lenses to access nested values
198
each_first_value = lens.Each()["values"][0]
199
first_values = each_first_value.collect()(data) # [1, 4]
200
201
# Function composition
202
multiply_by_ten = lens.Each() & (lambda x: x * 10)
203
result = multiply_by_ten([1, 2, 3]) # [10, 20, 30]
204
205
# Complex composition chains
206
complex_lens = (lens["data"]
207
.Each()
208
.Filter(lambda x: x > 0)
209
["value"]
210
.modify(lambda x: x * 2))
211
```