@@ -129,6 +129,11 @@ on-demand as we go along.
129129 is amazing stuff.
130130 - ** option** - an optional world for working with optional values.
131131 - ** result** - an error handling world for working with result values.
132+ - ** seq** - a world for working with sequences.
133+ - ** async_result** - an asynchronous error handling world for working
134+ with asynchronous result values.
135+ - ** async_option** - an asynchronous optional world for working with
136+ asynchronous optional values.
132137- ** Mailbox Processor** : for lock free programming using the [ Actor
133138 model] ( https://en.wikipedia.org/wiki/Actor_model ) .
134139- ** Cancellation Token** : for cancellation of asynchronous (and
@@ -419,6 +424,135 @@ A simplified type called `Try` is also available. It's a result type that is
419424pinned to ` Exception ` i.e., ` Result[TSource, Exception] ` .
420425
421426
427+ ### AsyncResult
428+
429+ The ` AsyncResult[T, TError] ` type is the asynchronous version of ` Result ` . It allows you
430+ to compose asynchronous operations that may fail, using the Result type. This is
431+ particularly useful for handling errors in asynchronous code, such as API calls,
432+ database operations, or any other I/O-bound tasks.
433+
434+ Similar to the ` Result ` effect, AsyncResult enables "railway oriented programming" but
435+ for asynchronous operations. If any part of the function yields an ` Error ` , the function
436+ is short-circuited and the following statements will never be executed.
437+
438+ ``` python
439+ from collections.abc import AsyncGenerator
440+
441+ from expression import Error, Ok, effect
442+
443+
444+ @effect.async_result [int, str]()
445+ async def fn () -> AsyncGenerator[int , int ]:
446+ x: int = yield 42 # Regular value
447+ y: int = yield await Ok(43 ) # Awaitable Ok value
448+
449+ # Short-circuit if condition is met
450+ if x + y > 80 :
451+ z: int = yield await Error(" Value too large" ) # This will short-circuit
452+ else :
453+ z: int = yield 44
454+
455+ yield x + y + z # Final value
456+
457+
458+ # This would be run in an async context
459+ # result = await fn()
460+ # assert result == Error("Value too large")
461+ ```
462+
463+ AsyncResult works well with other async functions and can be nested:
464+
465+
466+ ``` python
467+ @effect.async_result [int, str]()
468+ async def inner (x : int ) -> AsyncGenerator[int , int ]:
469+ y: int = yield x + 1
470+ yield y + 1 # Final value is y + 1
471+
472+
473+ @effect.async_result [int, str]()
474+ async def outer () -> AsyncGenerator[int , int ]:
475+ x: int = yield 40
476+
477+ # Call inner and await its result
478+ inner_result = await inner(x)
479+ y: int = yield await inner_result
480+
481+ yield y # Final value is y
482+
483+
484+ # This would be run in an async context
485+ # result = await outer()
486+ # assert result == Ok(42) # 40 -> 41 -> 42
487+ ```
488+
489+ A simplified type called ` AsyncTry ` is also available. It's an async result type that is
490+ pinned to ` Exception ` i.e., ` AsyncResult[TSource, Exception] ` .
491+
492+
493+ ### AsyncOption
494+
495+ The ` AsyncOption[T] ` type is the asynchronous version of ` Option ` . It allows you to
496+ compose asynchronous operations that may return an optional value, using the Option type.
497+ This is particularly useful for handling optional values in asynchronous code, such as
498+ API calls that might not return a value, database queries that might not find a record,
499+ or any other I/O-bound tasks that might not produce a meaningful result.
500+
501+ Similar to the ` Option ` effect, AsyncOption enables short-circuiting but for asynchronous
502+ operations. If any part of the function yields ` Nothing ` , the function is short-circuited
503+ and the following statements will never be executed.
504+
505+ ``` python
506+ from collections.abc import AsyncGenerator
507+
508+ from expression import Nothing, Some, effect
509+
510+
511+ @effect.async_option [int]()
512+ async def fn_option () -> AsyncGenerator[int , int ]:
513+ x: int = yield 42 # Regular value
514+ y: int = yield await Some(43 ) # Awaitable Some value
515+
516+ # Short-circuit if condition is met
517+ if x + y > 80 :
518+ z: int = yield await Nothing # This will short-circuit
519+ else :
520+ z: int = yield 44
521+
522+ yield x + y + z # Final value
523+
524+
525+ # This would be run in an async context
526+ # result = await fn_option()
527+ # assert result is Nothing
528+ ```
529+
530+ AsyncOption works well with other async functions and can be nested:
531+
532+
533+ ``` python
534+ @effect.async_option [int]()
535+ async def inner_option (x : int ) -> AsyncGenerator[int , int ]:
536+ y: int = yield x + 1
537+ yield y + 1 # Final value is y + 1
538+
539+
540+ @effect.async_option [int]()
541+ async def outer_option () -> AsyncGenerator[int , int ]:
542+ x: int = yield 40
543+
544+ # Call inner and await its result
545+ inner_result = await inner_option(x)
546+ y: int = yield await inner_result
547+
548+ yield y # Final value is y
549+
550+
551+ # This would be run in an async context
552+ # result = await outer_option()
553+ # assert result == Some(42) # 40 -> 41 -> 42
554+ ```
555+
422556### Sequence
423557
424558Sequences is a thin wrapper on top of iterables and contains operations for working with
0 commit comments