# apfel.container.maybe

*module*

A container that optionally holds a value.

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

A `Maybe` has two possible states, `Just` or `Nothing`. `Just` means a value is present, and `Nothing` means the value is absent.
The reason that we don't use `Some`-`None` or `Nil` nomenclature is to avoid [confusion with the built-in `None`](#rationale).

This module also provides a [`some`][apfel.container.maybe.some] constructor, which converts an `Optional[T]` value to a `Maybe[T]` value.

The [`Maybe`][apfel.container.maybe.Maybe] class, and the [`just`][apfel.container.maybe.just], [`nothing`][apfel.container.maybe.nothing], and [`some`][apfel.container.maybe.some] functions
are exposed in the [package namespace](../prelude.md#package-namespace).

## Rationale

Python has a built-in [:python `None`](https://docs.python.org/3/reference/datamodel.html#none) object that represents the absence of a value,
and a corresponding type hint [:python `Optional[T]`](https://docs.python.org/3/library/typing.html#typing.Optional).
However, an `Optional[T]` is semantically different from a `Maybe[T]` object.
An `Optional[T]` is a *union* of `T` and `None`, not a single object.
To use a union, you must explicitly check its type before every use.

```python
# Usage 1
if optional is None:
    ...
else:
    do_something(optional)

# Usage 2
do_something(optional) if optional is not None else ...

# Usage 3
optional is not None and do_something(optional)
```

On the other hand, a `Maybe[T]` object represents the absence of a value as a *state*.
Operations defined on `Maybe[T]` objects behave differently depending on the state of the object, but they are always available regardless of the state.

```python
j: Maybe[int] = just(42)
j.map(do_something) # `do_something` is called because `j` is `Just`.

n: Maybe[int] = nothing()
n.map(do_something) # `do_something` is not called because `n` is `Nothing`.
```

> **Warning**
>
> Notice that `None` **is not equal** to `Nothing`.
> Use `Maybe.is_nothing()` to check if a `Maybe` object is `Nothing`.
> 
> ```python
> n = nothing[int]()
> 
> assert n.is_nothing()
> assert n is not None
> assert n != None
> ```

## Implementation

`Maybe` implements the following interfaces:

| Interface | Methods |
| --- | --- |
| [`Functor`][apfel.core.monad.Functor] | [`map`][apfel.container.maybe.Maybe.map] |
| [`Applicative`][apfel.core.monad.Applicative] | [`pure`][apfel.container.maybe.Maybe.pure], [`apply`][apfel.container.maybe.Maybe.apply] |
| [`Monad`][apfel.core.monad.Monad] | [`bind`][apfel.container.maybe.Maybe.bind]([`and_then`][apfel.container.maybe.Maybe.and_then]) |

The `Maybe` class is a generic class that holds a value of type `T` inside `_val` field.
A boolean flag `_has_value` is used to indicate whether the value is present or absent.
If `_has_value` is `False`, reading from `_val` is an undefined behavior.

`Maybe` and its methods **do not** support inherit-based subclassing.

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

| Reference [:rust `Option`](https://doc.rust-lang.org/std/option/enum.Option.html) | Counterpart |
| --- | --- |
| `and` | [`and_`][apfel.container.maybe.Maybe.and_] |
| `and_then` | [`and_then`][apfel.container.maybe.Maybe.and_then] |
| `as_deref` | / |
| `as_deref_mut` | / |
| `as_mut` | / |
| `as_mut_slice` | / |
| `as_pin_mut` | / |
| `as_pin_ref` | / |
| `as_ref` | / |
| `as_slice` | / |
| `cloned` | - |
| `copied` | / |
| `expect` | [`expect`][apfel.container.maybe.Maybe.expect] |
| `filter` | [`filter`][apfel.container.maybe.Maybe.filter] |
| `flatten` | [~`flatten`][apfel.container.maybe.Maybe.flatten] |
| `get_or_insert` | [`get_or_insert`][apfel.container.maybe.Maybe.get_or_insert] |
| `get_or_insert_default` | / |
| `get_or_insert_with` | [`get_or_insert_with`][apfel.container.maybe.Maybe.get_or_insert_with] |
| `insert` | [`insert`][apfel.container.maybe.Maybe.insert] |
| `inspect` | [~`tap`][apfel.container.maybe.Maybe.tap] |
| `is_none` | [`is_nothing`][apfel.container.maybe.Maybe.is_nothing] |
| `is_some` | [`is_just`][apfel.container.maybe.Maybe.is_just] |
| `is_some_and` | [`is_just_and`][apfel.container.maybe.Maybe.is_just_and]|
| `iter` | - |
| `iter_mut` | / |
| `map` | [`map`][apfel.container.maybe.Maybe.map] |
| `map_or` | [`map_or`][apfel.container.maybe.Maybe.map_or] |
| `map_or_else` | [`map_or_else`][apfel.container.maybe.Maybe.map_or_else] |
| `ok_or` | [`ok_or`][apfel.container.maybe.Maybe.ok_or] |
| `ok_or_else` | [`ok_or_else`][apfel.container.maybe.Maybe.ok_or_else] |
| `or` | [`or_`][apfel.container.maybe.Maybe.or_] |
| `or_else` | [`or_else`][apfel.container.maybe.Maybe.or_else] |
| `replace` | [`replace`][apfel.container.maybe.Maybe.replace] |
| `take` | [`take`][apfel.container.maybe.Maybe.take] |
| `take_if` | [`take_if`][apfel.container.maybe.Maybe.take_if] |
| `transpose` | - |
| `unwrap` | [`unwrap`][apfel.container.maybe.Maybe.unwrap] |
| `unwrap_or` | [`unwrap_or`][apfel.container.maybe.Maybe.unwrap_or] |
| `unwrap_or_default` | / |
| `unwrap_or_else` | [`unwrap_or_else`][apfel.container.maybe.Maybe.unwrap_or_else] |
| `unwrap_unchecked` | [`unwrap_unchecked`][apfel.container.maybe.Maybe.unwrap_unchecked] |
| `unzip` | / |
| `xor` | [`xor`][apfel.container.maybe.Maybe.xor] |
| `zip` | [~`zip`][apfel.container.maybe.Maybe.zip] |
| `zip_with` | / |

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

## apfel.container.maybe.Maybe

*class*

```python
class Maybe(Monad)
```

Bases: `apfel.core.monad.Monad`

A container that optionally holds a value.
See [module-level documentation](maybe#maybe) for more information.

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/maybe.py#L136-L702)

### apfel.container.maybe.Maybe.__slots__

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

```python
__slots__: tuple[str, str] = ('_val', '_has_value')
```

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

### apfel.container.maybe.Maybe.__and__

*method*

```python
def __and__(other: Maybe[U], /) -> Maybe[U]
```

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

### apfel.container.maybe.Maybe.__bool__

*method*

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

Equivalent to [`is_just`][apfel.container.maybe.Maybe.is_just].

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

### apfel.container.maybe.Maybe.__class_getitem__

*method*

```python
def __class_getitem__(item) -> Maybe[U]
```

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

### apfel.container.maybe.Maybe.__eq__

*method*

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

If both values are `Just`, compare the inner values. Otherwise, return `True` if both are `Nothing`.

> **Warning**
>
> Notice that `None` is not equal to `Nothing`.

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

### apfel.container.maybe.Maybe.__hash__

*method*

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

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

### apfel.container.maybe.Maybe.__init__

*method*

```python
def __init__(val: T = ..., /, *, has_value: Literal[False] = True)
```

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

### apfel.container.maybe.Maybe.__len__

*method*

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

Return 1 if the value is `Just`, otherwise 0.

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

### apfel.container.maybe.Maybe.__or__

*method*

```python
def __or__(other: Maybe[T], /) -> Maybe[T]
```

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

### apfel.container.maybe.Maybe.__repr__

*method*

```python
def __repr__() -> str
```

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

### apfel.container.maybe.Maybe.__str__

*method*

```python
def __str__() -> str
```

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

### apfel.container.maybe.Maybe.and_

*method*

```python
def and_(other: Maybe[U], /) -> Maybe[U]
```

If the value is `Just`, return a shallow copy of the other `Maybe`. Otherwise, return a new `Nothing` of type `Maybe[U]`.

```python
j1 = just[int](42)
j2 = just[bool](True)

assert j1.and_(j2).unwrap() == True
assert (j1 & j2).unwrap() == True
assert (j1 & nothing[bool]()).is_nothing()
assert (nothing[int]() & j2).is_nothing()
```

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

### apfel.container.maybe.Maybe.and_then

*method*

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

If the value is `Just`, apply a function that maps the inner value to a `Maybe[U]` value. Otherwise, return `Nothing` of type `Maybe[U]`.

```python
j = just[int](114514)

assert j.and_then(lambda x: some(x + 1805296)).unwrap() == 1919810
```

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

### apfel.container.maybe.Maybe.apply

*method*

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

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

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

### apfel.container.maybe.Maybe.bind

*method*

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

Implementation of [`Monad.bind`][apfel.core.monad.Monad.bind].
Alias of [`and_then`][apfel.container.maybe.Maybe.and_then].

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

### apfel.container.maybe.Maybe.duplicate

*method* · *classmethod*

```python
def duplicate(value: Maybe[T], /) -> Maybe[T]
```

Create a shallow copy of a `Maybe` value.

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

### apfel.container.maybe.Maybe.expect

*method*

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

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

**Raises**

- `ValueError` — If the value is a `Nothing`.

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

### apfel.container.maybe.Maybe.filter

*method*

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

If the value is `Just` and satisfies the predicate, return the value. Otherwise, return `Nothing`.

```python
j = just[int](42)
assert j.filter(lambda x: x > 0).unwrap() == 42
assert j.filter(lambda x: x < 0).is_nothing()
```

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

### apfel.container.maybe.Maybe.flatten

*method*

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

Flatten a nested `Maybe` value for one level.
Unlike [:rust `Option::flatten`](https://doc.rust-lang.org/std/option/enum.Option.html#method.flatten), this method does not require the inner value to be a `Maybe`.
If it's not a nested `Maybe`, this is a no-op.

```python
j = just[Maybe[int]](just(42))
assert j.flatten() == just(42)

j2 = just[Maybe[Maybe[int]]](just(just(42)))
assert j2.flatten() == just(just(42))
assert j2.flatten().flatten() == just(42)
```

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

### apfel.container.maybe.Maybe.get_or_insert

*method*

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

Get the inner value, if any. Otherwise, insert the new value and return the value.

```python
j = just[int](42)
assert j.get_or_insert(114514) == 42

n = nothing[int]()
assert n.get_or_insert(114514) == 114514
```

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

### apfel.container.maybe.Maybe.get_or_insert_with

*method*

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

Get the inner value, if any. Otherwise, call a function to get a new value and return the value.

```python
j = just[int](42)
assert j.get_or_insert_with(lambda: 114514) == 42

n = nothing[int]()
assert n.get_or_insert_with(lambda: 114514) == 114514
```

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

### apfel.container.maybe.Maybe.insert

*method*

```python
def insert(value: T, /) -> T
```

Insert a value and returns it.

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

### apfel.container.maybe.Maybe.is_just

*method*

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

Check if the value is a `Just`.

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

### apfel.container.maybe.Maybe.is_just_and

*method*

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

Check if the value is a `Just` and satisfies the predicate.

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

### apfel.container.maybe.Maybe.is_nothing

*method*

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

Check if the value is a `Nothing`.

> **Note**
>
> A `Just(Nothing)` value of type `Maybe[Maybe[T]]` or a `Just(None)` value of type `Maybe[Optional[T]]` are not `Nothing`s.

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

### apfel.container.maybe.Maybe.make_just

*method* · *classmethod*

```python
def make_just(value: T, /) -> Self
```

Construct a `Just` value.

> **Warning**
>
> Prefer using [`just`][apfel.container.maybe.just] instead, unless in performance-critical code.

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

### apfel.container.maybe.Maybe.make_nothing

*method* · *classmethod*

```python
def make_nothing() -> Self
```

Construct a `Nothing` value.

> **Warning**
>
> Prefer using [`nothing`][apfel.container.maybe.nothing] instead, unless in performance-critical code.

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

### apfel.container.maybe.Maybe.make_some

*method* · *classmethod*

```python
def make_some(value: T | None, /) -> Self
```

Convert an `Optional[T]` value to a `Maybe` value.

> **Warning**
>
> Prefer using [`some`][apfel.container.maybe.some] function instead, unless in performance-critical code.

```python
some = Maybe.make_some(42)
assert some.is_just()

none = Maybe.make_some(None)
assert none.is_nothing()
```

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

### apfel.container.maybe.Maybe.map

*method*

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

Apply a function that maps the inner value to a new value, if any. Otherwise, return `Nothing`.

See [:rust `Option::map`](https://doc.rust-lang.org/std/option/enum.Option.html#method.map).

```python
j = just[int](42)
assert j.map(lambda x: x + 1) == just(43)

n = nothing[int]()
assert n.map(lambda x: x + 1) == nothing()
```

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

### apfel.container.maybe.Maybe.map_or

*method*

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

Map the inner value using a function, or use the default value if absent.

> **Tip**
>
> If the default value is an expensive expression, use [`map_or_else`][apfel.container.maybe.Maybe.map_or_else] instead.

```python
j = just[int](42)
n = nothing[int]()

assert j.map_or(0, lambda x: x + 1) == 43
assert n.map_or(0, lambda x: x + 1) == 0
```

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

### apfel.container.maybe.Maybe.map_or_else

*method*

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

Map the inner value using a function, or use a lazy default value if absent.

```python
j = just[int](42)
n = nothing[int]()

assert j.map_or_else(lambda: 0, lambda x: x + 1) == 43
assert n.map_or_else(lambda: 0, lambda x: x + 1) == 0
```

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

### apfel.container.maybe.Maybe.ok_or

*method*

```python
def ok_or(error: E, /) -> Result[T, E]
```

Convert the `Maybe` to a `Result`, converting `Just` to `Ok` and `Nothing` to a provided `Err` value.
The `Err` value is eagerly evaluated.

```python
j = just[int](42)
n = nothing[int]()

assert j.ok_or("error").unwrap() == 42
assert n.ok_or("error").unwrap_err() == "error"
```

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

### apfel.container.maybe.Maybe.ok_or_else

*method*

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

Convert the `Maybe` to a `Result`, converting `Just` to `Ok` and `Nothing` to a lazily evaluated `Err` value.

```python
j = just[int](42)
n = nothing[int]()

assert j.ok_or_else(lambda: 0).unwrap() == 42
assert n.ok_or_else(lambda: "error").unwrap_err() == "error"
```

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

### apfel.container.maybe.Maybe.or_

*method*

```python
def or_(other: Maybe[T], /) -> Maybe[T]
```

If the value is `Just`, return a shallow copy of itself. Otherwise, return the other `Maybe`'s shallow copy.

Notice that the right-hand side should be a `Maybe` object with the same inner type,
although this is not enforced at runtime.
And also this method does not short-circuit.

```python
j1 = just[int](42)
j2 = just[int](114514)

assert (j1 | j2).unwrap() == 42
assert (nothing[int]() | j2).unwrap() == 114514
assert (j1 | nothing[int]()).unwrap() == 42
```

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

### apfel.container.maybe.Maybe.or_else

*method*

```python
def or_else(func: Callable[[], Maybe[T]], /) -> Maybe[T]
```

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

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

### apfel.container.maybe.Maybe.pure

*method* · *classmethod*

```python
def pure(value, /) -> Maybe
```

Implementation of [`Applicative.pure`][apfel.core.monad.Applicative.pure], which is equivalent to [`Maybe.make_just`][apfel.container.maybe.Maybe.make_just].

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

### apfel.container.maybe.Maybe.replace

*method*

```python
def replace(value: T, /) -> Maybe[T]
```

Replace the inner value with a new value, returning the old value.
After replacement, `self` will always have a value.

```python
j = just[int](42)
old = j.replace(114514)
assert j == just(114514)
assert old == just(42)

n = nothing[int]()
old = n.replace(1919810)
assert n == just(1919810)
assert old == nothing()
```

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

### apfel.container.maybe.Maybe.take

*method*

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

Take the inner value out and leave no value in place.

```python
j = just[int](42)
out = j.take()
assert j.is_nothing()
assert out == just(42)
```

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

### apfel.container.maybe.Maybe.take_if

*method*

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

Take the inner value out if it satisfies the predicate, and leave no value in place.
Otherwise, take out nothing.

```python
j = just[int](42)
out = j.take_if(lambda x: x > 0)
assert j.is_nothing()
assert out == just(42)

j = just[int](42)
out = j.take_if(lambda x: x < 0)
assert j.is_just()
assert out == nothing()
```

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

### apfel.container.maybe.Maybe.tap

*method*

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

Call a function with the inner value, if any, and return the `Maybe` itself.
Unlike [:rust `Option::inspect`](https://doc.rust-lang.org/std/option/enum.Option.html#method.inspect), this method does not require the function to return `None`.

```python
j = just[int](42)
j.tap(print)  # prints 42
```

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

### apfel.container.maybe.Maybe.unwrap

*method*

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

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

```python
j = just[int](42)
n = nothing[int]()

assert j.unwrap() == 42

try: n.unwrap()
except ValueError: pass
else: assert False
```

**Raises**

- `ValueError` — If the value is a `Nothing`.

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

### apfel.container.maybe.Maybe.unwrap_or

*method*

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

Unwrap the inner value, or return a default value if absent.

```python
j = just[int](42)
n = nothing[int]()
assert j.unwrap_or(0) == 42
assert n.unwrap_or(0) == 0
```

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

### apfel.container.maybe.Maybe.unwrap_or_else

*method*

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

Unwrap the inner value, or return a value computed by a function if absent.

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

### apfel.container.maybe.Maybe.unwrap_unchecked

*method*

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

Return the inner value without checking if it is a `Just` or `Nothing`.

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

### apfel.container.maybe.Maybe.xor

*method*

```python
def xor(other: Maybe[T], /) -> Maybe[T]
```

If only one side has a value, return that side. Otherwise, return a `Nothing`.

```python
j1 = just[int](42)
j2 = just[int](114514)
assert j1.xor(j2).is_nothing()
```

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

### apfel.container.maybe.Maybe.zip

*method*

```python
def zip(*others: *tuple[()] | *tuple[Maybe[T1]] | *tuple[Maybe[T1], Maybe[T2]] | *tuple[Maybe[T1], Maybe[T2], Maybe[T3]] | *tuple[Maybe[T1], Maybe[T2], Maybe[T3], Maybe[T4]]) -> Maybe[tuple[T]] | Maybe[tuple[T, T1]] | Maybe[tuple[T, T1, T2]] | Maybe[tuple[T, T1, T2, T3]] | Maybe[tuple[T, T1, T2, T3, T4]]
```

Combine multiple `Maybe` values into a single `Maybe` value containing a tuple of them.
If all values are `Just`, return a `Just` value with a tuple of inner values.
Otherwise, return a `Nothing`.
Calling this method with no arguments is equivalent to calling `map` with a tuple constructor.

> **Warning**
>
> **Typing**
> 
> The type checker only supports zipping up to 5-tuple.

```python
j1 = just[int](42)
j2 = just[int](114514)
assert j1.zip(j2).unwrap() == (42, 114514)

n = nothing[int]()
assert j1.zip(n).is_nothing()
```

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

## apfel.container.maybe.just

*class*

```python
class just
```

Constructs a `Just` value.

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

```python
j: Maybe[int] = just(42)
j = just[int](42)

assert j.is_just()
assert j.unwrap() == 42
```

> **Warning**
>
> Calling `just(None)` will return a `Just(None)` value, not a `Nothing` value.
> If you want to map `None` to `Nothing`, use [`some`][apfel.container.maybe.some] instead.

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

### apfel.container.maybe.just.__match_args__

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

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

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

### apfel.container.maybe.just.__slots__

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

```python
__slots__ = ()
```

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

### apfel.container.maybe.just.__class_getitem__

*method*

```python
def __class_getitem__(item) -> Maybe[U]
```

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

### apfel.container.maybe.just.__instancecheck__

*method* · *classmethod*

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

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

### apfel.container.maybe.just.__new__

*method*

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

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

## apfel.container.maybe.nothing

*class*

```python
class nothing
```

Constructs a `Nothing` value.
Notice that this is not a literal.

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

```python
n: Maybe[int] = nothing()
n = nothing[int]()

assert n.is_nothing()
```

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

### apfel.container.maybe.nothing.__match_args__

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

```python
__match_args__ = ()
```

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

### apfel.container.maybe.nothing.__slots__

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

```python
__slots__ = ()
```

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

### apfel.container.maybe.nothing.__class_getitem__

*method*

```python
def __class_getitem__(item) -> Maybe[U]
```

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

### apfel.container.maybe.nothing.__instancecheck__

*method* · *classmethod*

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

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

### apfel.container.maybe.nothing.__new__

*method*

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

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

## apfel.container.maybe.some

*class*

```python
class some
```

Converts an `Optional[T]` to a `Maybe[T]` value.

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

```python
something: Maybe[int] = some(42)
assert something.is_just()
assert something.unwrap() == 42

something = some[int](None)
assert something.is_nothing()
```

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

### apfel.container.maybe.some.__slots__

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

```python
__slots__ = ()
```

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

### apfel.container.maybe.some.__class_getitem__

*method*

```python
def __class_getitem__(item) -> Maybe[U]
```

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

### apfel.container.maybe.some.__new__

*method*

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

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