0
# Conversions
1
2
Utilities for converting between different container types and integrating with external libraries and legacy code. These functions enable seamless interoperability between monadic containers and traditional Python code.
3
4
## Capabilities
5
6
### Container Type Conversions
7
8
Functions for converting between different container types while preserving semantic meaning.
9
10
```python { .api }
11
def result_to_maybe(result_container: Result[T, E]) -> Maybe[T]:
12
"""Convert Result to Maybe, discarding error information"""
13
14
def maybe_to_result(maybe_container: Maybe[T], default_error: E = None) -> Result[T, E]:
15
"""Convert Maybe to Result, providing error for Nothing case"""
16
17
def io_to_result(io_container: IO[T]) -> IOResult[T, Exception]:
18
"""Convert IO to IOResult by catching exceptions"""
19
20
def result_to_io(result_container: Result[T, E]) -> IO[Result[T, E]]:
21
"""Lift Result into IO context"""
22
23
def future_to_future_result(future_container: Future[T]) -> FutureResult[T, Never]:
24
"""Convert Future to FutureResult (never fails)"""
25
26
def future_result_to_future(future_result: FutureResult[T, E]) -> Future[Result[T, E]]:
27
"""Convert FutureResult to Future of Result"""
28
```
29
30
Usage examples:
31
32
```python
33
from returns.converters import result_to_maybe, maybe_to_result, io_to_result
34
from returns.result import Success, Failure
35
from returns.maybe import Some, Nothing
36
from returns.io import IO
37
38
# Result to Maybe conversion
39
success_result = Success(42)
40
maybe_from_success = result_to_maybe(success_result) # Some(42)
41
42
failure_result = Failure("error occurred")
43
maybe_from_failure = result_to_maybe(failure_result) # Nothing
44
45
# Maybe to Result conversion
46
some_value = Some(42)
47
result_from_some = maybe_to_result(some_value, "no value provided") # Success(42)
48
49
nothing_value = Nothing
50
result_from_nothing = maybe_to_result(nothing_value, "no value provided") # Failure("no value provided")
51
52
# Using default error
53
result_with_default = maybe_to_result(nothing_value) # Failure(None)
54
55
# IO to Result conversion (exception handling)
56
def risky_io_operation() -> str:
57
raise ValueError("Something went wrong")
58
59
io_operation = IO(risky_io_operation)
60
io_result = io_to_result(io_operation)
61
result = io_result() # Failure(ValueError("Something went wrong"))
62
```
63
64
### Flattening Operations
65
66
Utilities for flattening nested container structures.
67
68
```python { .api }
69
def flatten(container: Container[Container[T]]) -> Container[T]:
70
"""Join two nested containers together"""
71
72
def flatten_result(nested: Result[Result[T, E], E]) -> Result[T, E]:
73
"""Flatten nested Result containers"""
74
75
def flatten_maybe(nested: Maybe[Maybe[T]]) -> Maybe[T]:
76
"""Flatten nested Maybe containers"""
77
78
def flatten_io(nested: IO[IO[T]]) -> IO[T]:
79
"""Flatten nested IO containers"""
80
81
def flatten_future(nested: Future[Future[T]]) -> Future[T]:
82
"""Flatten nested Future containers"""
83
```
84
85
Usage examples:
86
87
```python
88
from returns.converters import flatten, flatten_result, flatten_maybe
89
from returns.result import Success, Failure
90
from returns.maybe import Some, Nothing
91
92
# Generic flatten
93
nested_success = Success(Success(42))
94
flattened = flatten(nested_success) # Success(42)
95
96
nested_failure_outer = Failure("outer error")
97
flattened_outer = flatten(nested_failure_outer) # Failure("outer error")
98
99
nested_failure_inner = Success(Failure("inner error"))
100
flattened_inner = flatten(nested_failure_inner) # Failure("inner error")
101
102
# Specific flatten operations
103
nested_maybe = Some(Some("hello"))
104
flattened_maybe = flatten_maybe(nested_maybe) # Some("hello")
105
106
nested_nothing = Some(Nothing)
107
flattened_nothing = flatten_maybe(nested_nothing) # Nothing
108
109
# Practical example: nested operations
110
def validate_input(s: str) -> Result[str, str]:
111
return Success(s.strip()) if s.strip() else Failure("Empty input")
112
113
def parse_number(s: str) -> Result[Result[int, str], str]:
114
validated = validate_input(s)
115
if isinstance(validated, Success):
116
try:
117
return Success(Success(int(validated.unwrap())))
118
except ValueError:
119
return Success(Failure("Not a number"))
120
return Failure("Validation failed")
121
122
# Without flatten: Result[Result[int, str], str]
123
nested_result = parse_number("42")
124
125
# With flatten: Result[int, str]
126
flattened_result = flatten(nested_result) # Success(42)
127
```
128
129
### Legacy Code Integration
130
131
Utilities for integrating with traditional Python code that doesn't use monadic containers.
132
133
```python { .api }
134
def unsafe_perform_io(io_container: IO[T]) -> T:
135
"""Execute IO operation and return raw value (unsafe)"""
136
137
def unwrap_or_failure(container: Container[T, E], failure_value: E) -> T | E:
138
"""Unwrap container value or return failure value"""
139
140
def to_optional(container: Maybe[T]) -> T | None:
141
"""Convert Maybe to optional value (T | None)"""
142
143
def from_optional(value: T | None) -> Maybe[T]:
144
"""Convert optional value to Maybe"""
145
146
def to_exception(container: Result[T, E]) -> T:
147
"""Convert Result to value or raise exception"""
148
149
def from_exception(func: Callable[..., T]) -> Callable[..., Result[T, Exception]]:
150
"""Convert exception-throwing function to Result-returning function"""
151
```
152
153
Usage examples:
154
155
```python
156
from returns.converters import (
157
unsafe_perform_io, to_optional, from_optional,
158
to_exception, from_exception
159
)
160
from returns.io import IO
161
from returns.maybe import Some, Nothing
162
from returns.result import Success, Failure, safe
163
164
# Unsafe IO execution (for integration with legacy code)
165
def read_config() -> str:
166
return "config_data"
167
168
io_config = IO(read_config)
169
config_data = unsafe_perform_io(io_config) # "config_data"
170
171
# Maybe to optional conversion
172
some_value = Some(42)
173
optional_value = to_optional(some_value) # 42
174
175
nothing_value = Nothing
176
optional_none = to_optional(nothing_value) # None
177
178
# Optional to Maybe conversion
179
optional_data = 42
180
maybe_data = from_optional(optional_data) # Some(42)
181
182
none_data = None
183
maybe_none = from_optional(none_data) # Nothing
184
185
# Result to exception conversion (for legacy APIs)
186
success_result = Success(42)
187
value = to_exception(success_result) # 42
188
189
failure_result = Failure(ValueError("Something went wrong"))
190
# value = to_exception(failure_result) # Raises ValueError("Something went wrong")
191
192
# Exception to Result conversion
193
def legacy_function(x: int) -> int:
194
if x < 0:
195
raise ValueError("Negative value")
196
return x * 2
197
198
safe_function = from_exception(legacy_function)
199
result1 = safe_function(5) # Success(10)
200
result2 = safe_function(-5) # Failure(ValueError("Negative value"))
201
```
202
203
### Async Conversions
204
205
Utilities for converting between sync and async containers.
206
207
```python { .api }
208
def sync_to_async(container: Container[T]) -> Future[Container[T]]:
209
"""Convert sync container to async Future"""
210
211
async def async_to_sync(future_container: Future[T]) -> T:
212
"""Convert async Future to sync value (requires await)"""
213
214
def result_to_future_result(result: Result[T, E]) -> FutureResult[T, E]:
215
"""Convert Result to FutureResult"""
216
217
async def future_result_to_result(future_result: FutureResult[T, E]) -> Result[T, E]:
218
"""Convert FutureResult to Result (requires await)"""
219
220
def io_to_future(io_container: IO[T]) -> Future[T]:
221
"""Convert IO to Future"""
222
223
def future_to_io(future_container: Future[T]) -> IO[Future[T]]:
224
"""Convert Future to IO of Future"""
225
```
226
227
Usage examples:
228
229
```python
230
import asyncio
231
from returns.converters import (
232
sync_to_async, result_to_future_result,
233
future_result_to_result, io_to_future
234
)
235
from returns.result import Success, Failure
236
from returns.future import Future, FutureResult
237
from returns.io import IO
238
239
# Sync to async conversion
240
sync_result = Success(42)
241
async_result = sync_to_async(sync_result)
242
future_success = await async_result # Success(42)
243
244
# Result to FutureResult
245
result = Success(42)
246
future_result = result_to_future_result(result)
247
converted_result = await future_result # Success(42)
248
249
# FutureResult to Result
250
async def async_operation() -> Result[int, str]:
251
return Success(42)
252
253
future_result = FutureResult(async_operation())
254
sync_result = await future_result_to_result(future_result) # Success(42)
255
256
# IO to Future
257
def io_operation() -> str:
258
return "data from IO"
259
260
io_container = IO(io_operation)
261
future_container = io_to_future(io_container)
262
result = await future_container # "data from IO"
263
```
264
265
### Type Narrowing
266
267
Utilities for type narrowing and runtime type checking with containers.
268
269
```python { .api }
270
def is_success(container: Result[T, E]) -> bool:
271
"""Check if Result is Success"""
272
273
def is_failure(container: Result[T, E]) -> bool:
274
"""Check if Result is Failure"""
275
276
def is_some(container: Maybe[T]) -> bool:
277
"""Check if Maybe is Some"""
278
279
def is_nothing(container: Maybe[T]) -> bool:
280
"""Check if Maybe is Nothing"""
281
282
def success_value(container: Result[T, E]) -> T | None:
283
"""Extract value from Success, None if Failure"""
284
285
def failure_value(container: Result[T, E]) -> E | None:
286
"""Extract error from Failure, None if Success"""
287
288
def some_value(container: Maybe[T]) -> T | None:
289
"""Extract value from Some, None if Nothing"""
290
```
291
292
Usage examples:
293
294
```python
295
from returns.converters import (
296
is_success, is_failure, success_value, failure_value,
297
is_some, some_value
298
)
299
from returns.result import Success, Failure
300
from returns.maybe import Some, Nothing
301
302
# Result type checking
303
success = Success(42)
304
failure = Failure("error")
305
306
print(is_success(success)) # True
307
print(is_failure(success)) # False
308
print(is_success(failure)) # False
309
print(is_failure(failure)) # True
310
311
# Value extraction
312
success_val = success_value(success) # 42
313
success_val_from_failure = success_value(failure) # None
314
failure_val = failure_value(failure) # "error"
315
failure_val_from_success = failure_value(success) # None
316
317
# Maybe type checking
318
some = Some(42)
319
nothing = Nothing
320
321
print(is_some(some)) # True
322
print(is_nothing(some)) # False
323
print(is_some(nothing)) # False
324
print(is_nothing(nothing)) # True
325
326
# Maybe value extraction
327
some_val = some_value(some) # 42
328
some_val_from_nothing = some_value(nothing) # None
329
```
330
331
## Integration Patterns
332
333
### Gradual Migration
334
335
```python
336
from returns.converters import from_exception, to_exception
337
from returns.result import Result
338
339
# Wrap legacy function
340
def legacy_divide(a: int, b: int) -> float:
341
return a / b # May raise ZeroDivisionError
342
343
# Create safe wrapper
344
safe_divide = from_exception(legacy_divide)
345
346
# Use in functional pipeline
347
def calculate_average(numbers: list[int]) -> Result[float, Exception]:
348
if not numbers:
349
return Failure(ValueError("Empty list"))
350
351
total = sum(numbers)
352
count = len(numbers)
353
354
return safe_divide(total, count)
355
356
# Convert back for legacy code when needed
357
def legacy_api_endpoint(numbers: list[int]) -> float:
358
result = calculate_average(numbers)
359
return to_exception(result) # Raises exception if failed
360
```
361
362
### External Library Integration
363
364
```python
365
from returns.converters import from_optional, to_optional
366
from returns.maybe import Maybe
367
import json
368
from typing import Any
369
370
# Integrate with libraries that return None for missing values
371
def parse_json_field(data: str, field: str) -> Maybe[Any]:
372
try:
373
parsed = json.loads(data)
374
field_value = parsed.get(field) # Returns None if missing
375
return from_optional(field_value)
376
except json.JSONDecodeError:
377
return Nothing
378
379
# Use in functional pipeline
380
def process_config(json_str: str) -> Maybe[str]:
381
return (
382
parse_json_field(json_str, "database")
383
.bind(lambda db_config: parse_json_field(str(db_config), "url"))
384
.map(str)
385
)
386
387
# Convert back to optional for external API
388
def get_database_url(json_str: str) -> str | None:
389
result = process_config(json_str)
390
return to_optional(result)
391
```
392
393
Conversion utilities provide essential bridges between the functional programming paradigm of Returns and traditional Python code, enabling gradual adoption and seamless integration with existing codebases and libraries.