# apfel.container.result

*module*

A container that holds either a success or a failure.

See [:rust `Result`](https://doc.rust-lang.org/std/result/enum.Result.html)
and [:haskell `Either`](https://hackage.haskell.org/package/base/docs/Data-Either.html).

A `Result` has two possible states, `Ok` or `Err`.
`Ok` means a successful value is present,
and `Err` means a failure value is present.

This module also provides a [`caught`][apfel.container.result.caught] decorator, which wraps a partial function to a total function returning a `Result`.

The [`Result`][apfel.container.result.Result] class, and the [`ok`][apfel.container.result.ok], [`err`][apfel.container.result.err], and [`caught`][apfel.container.result.caught] functions
are exposed in the [package namespace](../prelude.md#package-namespace).

## Rationale

Python [:python `raise`](https://docs.python.org/3/reference/simple_stmts.html#the-raise-statement)
is easily missed, since the gradual typing system does not support checked exceptions.
An alternative is to return [:golang nullable error flags](https://go.dev/blog/error-handling-and-go),
which is cumbersome to work with.

## Implementation

`Result`'s APIs are based on the Rust [:rust `Result`](https://doc.rust-lang.org/std/result/enum.Result.html),
and the comparison table is provided below.

| Reference [:rust `Result`](https://doc.rust-lang.org/std/result/enum.Result.html) | Counterpart |
| --- | --- |
| `and` | [`and_`][apfel.container.result.Result.and_] |
| `and_then` | [`and_then`][apfel.container.result.Result.and_then] |
| `as_deref` | / |
| `as_deref_mut` | / |
| `as_mut` | / |
| `as_ref` | / |
| `cloned` | - |
| `copied` | / |
| `err` | [`err`][apfel.container.result.Result.err] |
| `expect` | [`expect`][apfel.container.result.Result.expect] |
| `expect_err` | [`expect_err`][apfel.container.result.Result.expect_err] |
| `flatten` | [`flatten`][apfel.container.result.Result.flatten] |
| `inspect` | [~`tap`][apfel.container.result.Result.tap] |
| `inspect_err` | [~`tap_err`][apfel.container.result.Result.tap_err] |
| `into_err` | - |
| `into_ok` | - |
| `is_err` | [`is_err`][apfel.container.result.Result.is_err] |
| `is_err_and` | [`is_err_and`][apfel.container.result.Result.is_err_and] |
| `is_ok` | [`is_ok`][apfel.container.result.Result.is_ok] |
| `is_ok_and` | [`is_ok_and`][apfel.container.result.Result.is_ok_and] |
| `iter` | - |
| `iter_mut` | / |
| `map` | [`map`][apfel.container.result.Result.map] |
| `map_err` | [`map_err`][apfel.container.result.Result.map_err] |
| `map_or` | [`map_or`][apfel.container.result.Result.map_or] |
| `map_or_default` | / |
| `map_or_else` | [`map_or_else`][apfel.container.result.Result.map_or_else] |
| `ok` | [`ok`][apfel.container.result.Result.ok] |
| `or` | [`or_`][apfel.container.result.Result.or_] |
| `or_else` | [`or_else`][apfel.container.result.Result.or_else] |
| `transpose` | [~`transpose`][apfel.container.result.Result.transpose] |
| `unwrap` | [`unwrap`][apfel.container.result.Result.unwrap] |
| `unwrap_err` | [`unwrap_err`][apfel.container.result.Result.unwrap_err] |
| `unwrap_err_unchecked` | [`unwrap_err_unchecked`][apfel.container.result.Result.unwrap_err_unchecked] |
| `unwrap_or` | [`unwrap_or`][apfel.container.result.Result.unwrap_or] |
| `unwrap_or_default` | / |
| `unwrap_or_else` | [`unwrap_or_else`][apfel.container.result.Result.unwrap_or_else] |
| `unwrap_unchecked` | [`unwrap_unchecked`][apfel.container.result.Result.unwrap_unchecked] |

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/container/result.py#L1-L1)

## apfel.container.result.Result

*class*

```python
class Result(Monad)
```

Bases: `apfel.core.monad.Monad`

A container that holds either a success or a failure.
See [module-level documentation](result#result) for more details.

This class is exposed in the [package namespace](../prelude.md#package-namespace).

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/container/result.py#L84-L398)

### apfel.container.result.Result.__slots__

*attribute* · *class attribute* · *instance attribute*

```python
__slots__ = ('_val', '_is_ok')
```

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/container/result.py#L92-L92)

### apfel.container.result.Result.__and__

*method*

```python
def __and__(other: Self) -> Self
```

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/container/result.py#L15-L15)

### apfel.container.result.Result.__bool__

*method*

```python
def __bool__() -> bool
```

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/container/result.py#L157-L158)

### apfel.container.result.Result.__class_getitem__

*method*

```python
def __class_getitem__(item)
```

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/container/result.py#L98-L99)

### apfel.container.result.Result.__eq__

*method*

```python
def __eq__(other: Self, /) -> bool
```

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/container/result.py#L166-L169)

### apfel.container.result.Result.__hash__

*method*

```python
def __hash__() -> int
```

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/container/result.py#L205-L206)

### apfel.container.result.Result.__init__

*method*

```python
def __init__(value: T, /, *, is_ok: bool = True)
```

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/container/result.py#L94-L96)

### apfel.container.result.Result.__or__

*method*

```python
def __or__(other: Self) -> Self
```

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/container/result.py#L42-L42)

### apfel.container.result.Result.__repr__

*method*

```python
def __repr__()
```

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/container/result.py#L291-L296)

### apfel.container.result.Result.__str__

*method*

```python
def __str__()
```

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/container/result.py#L298-L299)

### apfel.container.result.Result.and_

*method*

```python
def and_(other: Self, /) -> Self
```

If the value is `Ok`, return a shallow copy of the other `Result`. Otherwise, return a new `Err` of type `Result[T, E]`.

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/container/result.py#L115-L123)

### apfel.container.result.Result.and_then

*method*

```python
def and_then(func: Callable[[T], Result[U, E]], /) -> Result[U, E]
```

If the value is `Ok`, apply a function that maps the inner value to a `Result[U, E]` value. Otherwise, return `Err` of type `Result[U, E]`.

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/container/result.py#L127-L131)

### apfel.container.result.Result.apply

*method*

```python
def apply(func: Result[Callable[[T], U], E], /) -> Result[U, E]
```

Implementation of [`Applicative.apply`][apfel.core.monad.Applicative.apply].
Applies the callable wrapped within a `Result` to the inner value, if both are `Ok`.

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/container/result.py#L133-L148)

### apfel.container.result.Result.bind

*method*

```python
def bind(func: Callable[[T], Result[U, E]], /) -> Result[U, E]
```

Implementation of [`Monad.bind`][apfel.core.monad.Monad.bind].
Alias of [`and_then`][apfel.container.result.Result.and_then].

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/container/result.py#L150-L155)

### apfel.container.result.Result.done

*method*

```python
def done() -> tuple[T, None] | tuple[None, E]
```

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/container/result.py#L160-L164)

### apfel.container.result.Result.err

*method*

```python
def err() -> Maybe[E]
```

Convert a `Result[T, E]` to a `Maybe[E]`.

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/container/result.py#L171-L179)

### apfel.container.result.Result.expect

*method*

```python
def expect(message: str, /) -> T
```

Unwrap the inner `Ok` value, if any. Otherwise, raise a `ValueError` with a custom message.

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/container/result.py#L181-L187)

### apfel.container.result.Result.expect_err

*method*

```python
def expect_err(message: str, /) -> E
```

Unwrap the inner `Err` value, if any. Otherwise, raise a `ValueError` with a custom message.

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/container/result.py#L189-L195)

### apfel.container.result.Result.flatten

*method*

```python
def flatten() -> Result[T_, E]
```

Flatten a nested `Result` (`Result[Result[T, E], E]`) value for one level (`Result[T, E]`).

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/container/result.py#L197-L203)

### apfel.container.result.Result.is_err

*method*

```python
def is_err() -> bool
```

Check if the value is an `Err`.

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/container/result.py#L208-L212)

### apfel.container.result.Result.is_err_and

*method*

```python
def is_err_and(pred: Callable[[E], bool], /) -> bool
```

Check if the value is an `Err` and satisfies the predicate.

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/container/result.py#L214-L218)

### apfel.container.result.Result.is_ok

*method*

```python
def is_ok() -> bool
```

Check if the value is an `Ok`.

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/container/result.py#L220-L224)

### apfel.container.result.Result.is_ok_and

*method*

```python
def is_ok_and(pred: Callable[[T], bool], /) -> bool
```

Check if the value is an `Ok` and satisfies the predicate.

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/container/result.py#L226-L230)

### apfel.container.result.Result.make_err

*method* · *classmethod*

```python
def make_err(value: E, /) -> Result[T, E]
```

Construct an `Err` value.

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/container/result.py#L108-L113)

### apfel.container.result.Result.make_ok

*method* · *classmethod*

```python
def make_ok(value: T, /) -> Result[T, E]
```

Construct an `Ok` value.

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/container/result.py#L101-L106)

### apfel.container.result.Result.map

*method*

```python
def map(func: Callable[[T], U], /) -> Result[U, E]
```

Map a `Result[T, E]` to `Result[U, E]` by applying a function to a contained `Ok` value, leaving an `Err` value untouched.

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/container/result.py#L232-L238)

### apfel.container.result.Result.map_err

*method*

```python
def map_err(func: Callable[[E], F], /) -> Result[T, F]
```

Map a `Result[T, E]` to `Result[T, F]` by applying a function to a contained `Err` value, leaving an `Ok` value untouched.

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/container/result.py#L240-L244)

### apfel.container.result.Result.map_or

*method*

```python
def map_or(default: U, func: Callable[[T], U]) -> U
```

Apply a function to a contained `Ok` value, or return a provided default value.

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/container/result.py#L246-L250)

### apfel.container.result.Result.map_or_else

*method*

```python
def map_or_else(default: Callable[[E], U], func: Callable[[T], U]) -> U
```

Map a `Result[T, E]` to `U` by applying a function to a contained `Ok` value, or a fallback function to a contained `Err` value.

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/container/result.py#L252-L256)

### apfel.container.result.Result.ok

*method*

```python
def ok() -> Maybe[T]
```

Convert a `Result[T, E]` to a `Maybe[T]`.

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/container/result.py#L258-L266)

### apfel.container.result.Result.or_

*method*

```python
def or_(other: Self, /) -> Self
```

If the value is `Err`, return a shallow copy of the other `Result`. Otherwise, return a new `Ok` of type `Result[T, F]`.

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/container/result.py#L268-L274)

### apfel.container.result.Result.or_else

*method*

```python
def or_else(func: Callable[[E], Self], /) -> Self
```

Return a shallow copy of the `Result` if it contains an `Ok` value, otherwise call a function to get a result.

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/container/result.py#L278-L282)

### apfel.container.result.Result.pure

*method* · *classmethod*

```python
def pure(value: T, /) -> Result[T, E]
```

Implementation of [`Applicative.pure`][apfel.core.monad.Applicative.pure], which is equivalent to [`Result.make_ok`][apfel.container.result.Result.make_ok].

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/container/result.py#L284-L289)

### apfel.container.result.Result.tap

*method*

```python
def tap(func: Callable[[T], Any], /) -> Self
```

Call a function with the contained `Ok` value if it exists.

Unlike [:rust `Result::inspect`](https://doc.rust-lang.org/std/result/enum.Result.html#method.inspect),
this method does not require the function to return `None`.

```python
some_ok = ok(5)
some_err = err("error")
some_ok.tap(print)  # prints: 5
some_err.tap(print)  # prints nothing
```

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/container/result.py#L301-L317)

### apfel.container.result.Result.tap_err

*method*

```python
def tap_err(func: Callable[[E], Any], /) -> Self
```

Call a function with the contained `Err` value if it exists.

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/container/result.py#L319-L325)

### apfel.container.result.Result.throw

*method*

```python
def throw() -> T
```

Raise the contained exception if it is an `Err`. Otherwise, return the inner `Ok` value.

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/container/result.py#L327-L335)

### apfel.container.result.Result.transpose

*method*

```python
def transpose() -> Maybe[Result[U, E]]
```

Transpose a `Result` of a `Maybe` into a `Maybe` of a `Result`.
`Result[Maybe[T], E]` -> `Maybe[Result[T, E]]`

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/container/result.py#L337-L354)

### apfel.container.result.Result.unwrap

*method*

```python
def unwrap() -> T
```

Unwrap the inner `Ok` value, if any. Otherwise, raise a `ValueError`.

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/container/result.py#L356-L364)

### apfel.container.result.Result.unwrap_err

*method*

```python
def unwrap_err() -> E
```

Unwrap the inner `Err` value, if any. Otherwise, raise a `ValueError`.

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/container/result.py#L378-L386)

### apfel.container.result.Result.unwrap_err_unchecked

*method*

```python
def unwrap_err_unchecked() -> E
```

Return the inner `Err` value without checking if it is an `Err`.

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/container/result.py#L394-L398)

### apfel.container.result.Result.unwrap_or

*method*

```python
def unwrap_or(default: T, /) -> T
```

Unwrap the inner `Ok` value, or return a default value if contains an `Err`.

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/container/result.py#L366-L370)

### apfel.container.result.Result.unwrap_or_else

*method*

```python
def unwrap_or_else(func: Callable[[E], T], /) -> T
```

Unwrap the inner `Ok` value, or return a value computed by a function if contains an `Err`.

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/container/result.py#L372-L376)

### apfel.container.result.Result.unwrap_unchecked

*method*

```python
def unwrap_unchecked() -> T
```

Return the inner value without checking if it is an `Ok` or `Err`.

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/container/result.py#L388-L392)

## apfel.container.result.caught

*class*

```python
class caught
```

A decorator that wraps a partial function to a total function returning a `Result`.

It supports multiple usages:

- Use as a decorator without arguments (`@caught`) to catch all exceptions.
- Use as a decorator with specific exception types (either type union `@caught(ExceptionA | ExceptionB)` or args `@caught(ExceptionA, ExceptionB)`) to catch only those exceptions.
- Use as a higher-order function by passing the target function (`caught(func)`) to catch all exceptions.
- Use as a higher-order function with specific exception types as args (`caught(func, ExceptionA, ExceptionB)`) to catch only those exceptions.
- Use generic syntax to provide type hints (`@caught[ExceptionA]`, `@caught[ExceptionA]()`, `caught[ExceptionA]()`), *without affecting runtime behavior*.

This function is exposed in the [package namespace](../prelude.md#package-namespace).

```python
@caught(ZeroDivisionError)
def divide(a: float, b: float) -> float:
    return a / b

divide(4, 2)  # Ok(2.0)
divide(4, 0)  # Err(ZeroDivisionError)
```

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/container/result.py#L468-L525)

### apfel.container.result.caught.__class_getitem__

*method*

```python
def __class_getitem__(item: type[F]) -> type[caught[F, T]]
```

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/container/result.py#L492-L493)

### apfel.container.result.caught.__new__

*method*

```python
def __new__(first=None, /, *exceptions: type[Es]) -> Callable[[Callable[P, U]], Callable[P, Result[U, E]]] | Callable[[Callable[P, U]], Callable[P, Result[U, F]]] | Callable[[Callable[P, U]], Callable[P, Result[U, E0 | Es]]] | Callable[P, Result[U, Es]] | Callable[P, Result[U, E]]
```

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/container/result.py#L506-L525)

## apfel.container.result.err

*class*

```python
class err
```

Construct an `Err` value.

This function is exposed in the [package namespace](../prelude.md#package-namespace).

```python
some_err = err("Something went wrong")
match some_err:
    case ok(value):
        print(f"Got an Ok with value: {value}")
    case err(error):
        print(f"Got an Err with error: {error}")

# Output: Got an Err with error: Something went wrong
```

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/container/result.py#L435-L465)

### apfel.container.result.err.__match_args__

*attribute* · *class attribute* · *instance attribute*

```python
__match_args__ = ('_val')
```

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/container/result.py#L455-L455)

### apfel.container.result.err.__slots__

*attribute* · *class attribute* · *instance attribute*

```python
__slots__ = ()
```

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/container/result.py#L454-L454)

### apfel.container.result.err.__class_getitem__

*method*

```python
def __class_getitem__(item)
```

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/container/result.py#L457-L458)

### apfel.container.result.err.__instancecheck__

*method* · *classmethod*

```python
def __instancecheck__(instance)
```

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/container/result.py#L463-L465)

### apfel.container.result.err.__new__

*method*

```python
def __new__(value: E, /) -> Result[T, E]
```

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/container/result.py#L460-L461)

## apfel.container.result.ok

*class*

```python
class ok
```

Construct an `Ok` value.

This function is exposed in the [package namespace](../prelude.md#package-namespace).

```python
some_ok = ok(42)

match some_ok:
    case ok(value):
        print(f"Got an Ok with value: {value}")
    case err(error):
        print(f"Got an Err with error: {error}")

# Output: Got an Ok with value: 42
```

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/container/result.py#L401-L432)

### apfel.container.result.ok.__match_args__

*attribute* · *class attribute* · *instance attribute*

```python
__match_args__ = ('_val')
```

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/container/result.py#L422-L422)

### apfel.container.result.ok.__slots__

*attribute* · *class attribute* · *instance attribute*

```python
__slots__ = ()
```

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/container/result.py#L421-L421)

### apfel.container.result.ok.__class_getitem__

*method*

```python
def __class_getitem__(item)
```

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/container/result.py#L424-L425)

### apfel.container.result.ok.__instancecheck__

*method* · *classmethod*

```python
def __instancecheck__(instance)
```

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/container/result.py#L430-L432)

### apfel.container.result.ok.__new__

*method*

```python
def __new__(value: T, /) -> Result[T, E]
```

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/container/result.py#L427-L428)
