0
# Utility Types
1
2
Supporting types and systems that enhance the lens library's functionality, including Maybe monad for optional values, type class system for functional programming patterns, and hooks system for extending support to custom data types.
3
4
## Capabilities
5
6
### Maybe Type System
7
8
Optional value handling inspired by functional programming, providing safe operations on values that may or may not exist.
9
10
```python { .api }
11
class Just:
12
"""Container for a value that exists."""
13
def __init__(self, item: A) -> None: ...
14
15
def map(self, fn: Callable[[A], B]) -> Just[B]:
16
"""Apply function to contained value."""
17
18
def maybe(self, guard: B) -> Union[A, B]:
19
"""Extract value or return guard if Nothing."""
20
21
def unwrap(self) -> A:
22
"""Extract value (raises if Nothing)."""
23
24
def is_nothing(self) -> bool:
25
"""Check if this is Nothing."""
26
27
def __add__(self, other: Just[A]) -> Just[A]: ...
28
def __eq__(self, other: object) -> bool: ...
29
def __iter__(self) -> Iterator[A]: ...
30
31
class Nothing(Just):
32
"""Empty container representing no value."""
33
def __init__(self) -> None: ...
34
35
def map(self, fn: Callable[[A], B]) -> Just[B]:
36
"""Always returns Nothing."""
37
38
def maybe(self, guard: B) -> Union[A, B]:
39
"""Always returns guard."""
40
41
def unwrap(self) -> A:
42
"""Always raises ValueError."""
43
44
def is_nothing(self) -> bool:
45
"""Always returns True."""
46
```
47
48
#### Usage Examples
49
50
```python
51
from lenses.maybe import Just, Nothing
52
53
# Creating Maybe values
54
some_value = Just(42)
55
no_value = Nothing()
56
57
# Safe operations
58
result1 = some_value.map(lambda x: x * 2) # Just(84)
59
result2 = no_value.map(lambda x: x * 2) # Nothing()
60
61
# Extracting values safely
62
value1 = some_value.maybe(0) # 42
63
value2 = no_value.maybe(0) # 0 (guard value)
64
65
# Checking for values
66
print(some_value.is_nothing()) # False
67
print(no_value.is_nothing()) # True
68
69
# Unwrapping (dangerous)
70
actual_value = some_value.unwrap() # 42
71
# no_value.unwrap() # Raises ValueError
72
73
# Used with lenses
74
from lenses import lens
75
data = [Just(1), Nothing(), Just(3), Nothing(), Just(5)]
76
values = lens.Each().Just().collect()(data) # [1, 3, 5]
77
```
78
79
### Type Class System
80
81
Functional programming type classes providing generic operations for different data types.
82
83
```python { .api }
84
# Monoid operations
85
def mempty(monoid: Any) -> Any:
86
"""Get the empty/identity value for a monoid type."""
87
88
def mappend(monoid: Any, other: Any) -> Any:
89
"""Combine two monoid values."""
90
91
# Functor operations
92
def fmap(functor: Any, func: Callable[[Any], Any]) -> Any:
93
"""Apply function inside a functor context."""
94
95
# Applicative operations
96
def pure(applicative: Any, item: B) -> Any:
97
"""Wrap a value in an applicative context."""
98
99
def apply(applicative: Any, func: Any) -> Any:
100
"""Apply wrapped function to wrapped value."""
101
```
102
103
#### Built-in Type Support
104
105
```python { .api }
106
# Monoid instances for built-in types
107
mempty(0) # -> 0 (int)
108
mempty("") # -> "" (str)
109
mempty([]) # -> [] (list)
110
mempty({}) # -> {} (dict)
111
mempty((1, 2)) # -> (0, 0) (tuple)
112
113
# Mappend instances
114
mappend(1, 2) # -> 3 (int addition)
115
mappend("a", "b") # -> "ab" (str concatenation)
116
mappend([1], [2]) # -> [1, 2] (list concatenation)
117
mappend({"a": 1}, {"b": 2}) # -> {"a": 1, "b": 2} (dict merge)
118
119
# Functor instances
120
fmap([1, 2, 3], lambda x: x * 2) # -> [2, 4, 6] (list)
121
fmap((1, 2, 3), lambda x: x * 2) # -> (2, 4, 6) (tuple)
122
123
# Applicative instances
124
pure([], 42) # -> [42] (list)
125
apply([1, 2], [lambda x: x * 2, lambda x: x + 1]) # -> [2, 4, 2, 3]
126
```
127
128
#### Usage Examples
129
130
```python
131
from lenses.typeclass import mempty, mappend, fmap
132
133
# Working with monoids
134
empty_list = mempty([1, 2, 3]) # []
135
combined = mappend([1, 2], [3, 4]) # [1, 2, 3, 4]
136
137
# String concatenation through mappend
138
greeting = mappend("Hello, ", "World!") # "Hello, World!"
139
140
# Dictionary merging
141
config1 = {"debug": True, "port": 8080}
142
config2 = {"host": "localhost", "port": 3000}
143
merged = mappend(config1, config2) # {"debug": True, "port": 3000, "host": "localhost"}
144
145
# Functor mapping
146
squared = fmap([1, 2, 3, 4], lambda x: x ** 2) # [1, 4, 9, 16]
147
148
# Used internally by lenses for monoid operations
149
from lenses import lens
150
data = [[], [1], [2, 3]]
151
combined_lists = lens.Each().get_monoid()(data) # [1, 2, 3]
152
```
153
154
### Const Functor
155
156
Constant functor used internally for lens getting operations.
157
158
```python { .api }
159
class Const:
160
"""Functor that ignores the wrapped type and preserves constant value."""
161
def __init__(self, item: C) -> None: ...
162
163
def map(self, func: Callable[[A], B]) -> Const[C, B]:
164
"""Ignores function, returns Const with same value."""
165
166
def pure(self, item: D) -> Const[D, B]:
167
"""Creates empty Const."""
168
169
def apply(self, fn: Const[C, Callable[[A], B]]) -> Const[C, B]:
170
"""Combines constant values using mappend."""
171
172
def unwrap(self) -> C:
173
"""Extract the constant value."""
174
175
def __eq__(self, other: object) -> bool: ...
176
```
177
178
#### Usage Examples
179
180
```python
181
from lenses.const import Const
182
183
# Const preserves values through transformations
184
const_val = Const(42)
185
mapped = const_val.map(lambda x: x * 1000) # Still Const(42)
186
print(mapped.unwrap()) # 42
187
188
# Used internally by lens operations
189
# This is mostly internal to the lens library
190
```
191
192
### Identity Functor
193
194
Identity wrapper functor used internally for lens setting operations.
195
196
```python { .api }
197
class Identity:
198
"""Simple wrapper functor that preserves identity."""
199
def __init__(self, item: A) -> None: ...
200
def unwrap(self) -> A: ...
201
def map(self, func: Callable[[A], B]) -> Identity[B]: ...
202
```
203
204
### Hooks System
205
206
Extension system allowing custom data types to work with lenses.
207
208
```python { .api }
209
# Core hook functions (using singledispatch)
210
def contains_add(container, item):
211
"""Add item to container."""
212
213
def contains_remove(container, item):
214
"""Remove item from container."""
215
216
def from_iter(prototype, iterator):
217
"""Reconstruct object from iterator."""
218
219
def setattr(obj, name, value):
220
"""Set object attribute."""
221
222
def setitem(obj, key, value):
223
"""Set container item."""
224
225
def to_iter(obj):
226
"""Convert object to iterator."""
227
```
228
229
#### Extending with Custom Types
230
231
```python
232
from lenses.hooks import from_iter, to_iter
233
from functools import singledispatch
234
235
# Example: Adding support for custom collection type
236
class MyList:
237
def __init__(self, items):
238
self._items = list(items)
239
240
def __iter__(self):
241
return iter(self._items)
242
243
# Register hooks for your type
244
@from_iter.register(MyList)
245
def _mylist_from_iter(prototype, iterator):
246
return MyList(iterator)
247
248
@to_iter.register(MyList)
249
def _mylist_to_iter(obj):
250
return iter(obj._items)
251
252
# Now MyList works with lenses
253
from lenses import lens
254
my_data = MyList([1, 2, 3, 4])
255
doubled = lens.Each().modify(lambda x: x * 2)(my_data) # MyList([2, 4, 6, 8])
256
```
257
258
### Pyrsistent Integration
259
260
Optional integration with the pyrsistent library for enhanced immutable data structures.
261
262
```python { .api }
263
# Automatic registration when pyrsistent is available
264
# Supports: PVector, PList, PMap, PSet, etc.
265
266
# No additional imports needed if pyrsistent is installed
267
# pip install pyrsistent
268
```
269
270
#### Usage Examples
271
272
```python
273
# With pyrsistent installed
274
import pyrsistent as pyr
275
from lenses import lens
276
277
# Works automatically with pyrsistent collections
278
plist = pyr.v(1, 2, 3, 4) # PVector
279
doubled = lens.Each().modify(lambda x: x * 2)(plist) # PVector([2, 4, 6, 8])
280
281
pmap = pyr.m(a=1, b=2, c=3) # PMap
282
incremented = lens.Values().modify(lambda x: x + 1)(pmap) # PMap({'a': 2, 'b': 3, 'c': 4})
283
```
284
285
### Functorisor
286
287
Advanced functor adapter utilities for internal lens operations.
288
289
```python { .api }
290
class Functorisor:
291
"""Functor adapter for complex lens operations."""
292
# Internal implementation details
293
# Not typically used directly by end users
294
```
295
296
### Method Shortcuts
297
298
The lens system provides convenient method shortcuts for common operations.
299
300
```python { .api }
301
# Available on lens objects:
302
# call_methodname(*args, **kwargs) - shortcut for call('methodname', *args, **kwargs)
303
# call_mut_methodname(*args, **kwargs) - shortcut for call_mut('methodname', *args, **kwargs)
304
```
305
306
#### Usage Examples
307
308
```python
309
from lenses import lens
310
311
# Method call shortcuts
312
data = ['hello', 'world', 'python']
313
314
# Regular method calls
315
uppercased1 = lens.Each().call('upper')(data) # ['HELLO', 'WORLD', 'PYTHON']
316
317
# Shortcut syntax
318
uppercased2 = lens.Each().call_upper()(data) # ['HELLO', 'WORLD', 'PYTHON']
319
320
# Mutable method shortcuts
321
data = [[3, 1, 2], [6, 4, 5]]
322
sorted_data = lens.Each().call_mut_sort()(data) # [[1, 2, 3], [4, 5, 6]]
323
```
324
325
### Arithmetic and Comparison Operations
326
327
Lens objects support arithmetic and comparison operations through the modify interface.
328
329
```python { .api }
330
# Arithmetic operations (via modify)
331
lens_obj + value # Equivalent to lens_obj.modify(lambda x: x + value)
332
lens_obj - value # Equivalent to lens_obj.modify(lambda x: x - value)
333
lens_obj * value # Equivalent to lens_obj.modify(lambda x: x * value)
334
lens_obj / value # Equivalent to lens_obj.modify(lambda x: x / value)
335
# ... and many more operators
336
337
# Comparison operations
338
lens_obj == value # Equivalent to lens_obj.modify(lambda x: x == value)
339
lens_obj < value # Equivalent to lens_obj.modify(lambda x: x < value)
340
# ... and other comparison operators
341
```
342
343
#### Usage Examples
344
345
```python
346
from lenses import lens
347
348
# Arithmetic operations
349
data = [1, 2, 3, 4, 5]
350
incremented = (lens.Each() + 1)(data) # [2, 3, 4, 5, 6]
351
doubled = (lens.Each() * 2)(data) # [2, 4, 6, 8, 10]
352
353
# Comparison operations
354
greater_than_3 = (lens.Each() > 3)(data) # [False, False, False, True, True]
355
356
# Bitwise operations (special case)
357
data = [1, 2, 3, 4]
358
bitwise_result = lens.Each().bitwise_and(5)(data) # [1, 0, 1, 4]
359
```