# apfel.core.monad

*module*

> **Meme**
>
> <del>A monad is a **monoid** in the category of **endofunctors**.</del>

Monadic interfaces that enable
structured ways to compose and manipulate computations on a single effectful construction.

The module defines three abstract classes: [`Functor`][apfel.core.monad.Functor],
[`Applicative`][apfel.core.monad.Applicative], and [`Monad`][apfel.core.monad.Monad].

## Rationale

Monadic abstractions like [:haskell `Functor`](https://hackage.haskell.org/package/base/docs/Data-Functor.html), [:haskell `Applicative`](https://hackage.haskell.org/package/base/docs/Control-Applicative.html), and [:haskell `Monad`](https://hackage.haskell.org/package/base/docs/Control-Monad.html) are popularized by Haskell.
Although Python has weak support for functional programming, we include these abstractions to provide a uniform interface for such calculations.

Under the hood, these abstractions use dynamic single dispatch provided in [`apfel.core.dispatch`](dispatch.md), which
allows us to define monadic helper functions for standard built-in types.
This module provides default implementations for `list`, `tuple`, `set`, and `function` as `Functor`, `Applicative`, and `Monad`, `dict` as `Functor`.

Note that we loosen the constraints of such abstractions, as writing pure functional code is not a goal of this library.

## Usage

Here's a high-level comparison of the three.
Assume `Value` is a `Monad`.
**A `Monad` is always a `Functor` and an `Applicative`.**

```python

value = Value(42)

assert value.map  (      lambda x: x + 1 ) == Value(43)
assert value.apply(Value(lambda x: x + 1)) == Value(43)
assert value.bind (lambda x: Value(x + 1)) == Value(43)

```

If you are familiar with Rust,
[:rust `Option`](https://doc.rust-lang.org/std/option/enum.Option.html) is a `Monad`,
[:rust `Option.map`](https://doc.rust-lang.org/std/option/enum.Option.html#method.map) is its `Functor.map`,
[:rust `Option.and_then`](https://doc.rust-lang.org/std/option/enum.Option.html#method.and_then) is its `Monad.bind`.

## Case: `list`

```python
assert Functor.map([1, 2, 3], lambda x: x + 1) == [2, 3, 4]
assert Applicative.apply([1, 2, 3], [lambda x: x + 1, lambda x: x + 2]) == [2, 3, 4, 3, 4, 5]
assert Monad.bind([1, 2, 3], lambda x: [x, x + 1]) == [1, 2, 2, 3, 3, 4]
```

## Case: `function`

`Functor.map` of a function is exactly a composition of functions.

```python
assert Functor.map(lambda x: x * 2, lambda x: x + 1)(2) == 5
```

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

## apfel.core.monad.fmap

*attribute* · *module attribute*

```python
fmap = Functor.map
```

An alias for [`Functor.map`][apfel.core.monad.Functor.map].

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/core/monad/__init__.py#L250-L250)

## apfel.core.monad.Applicative

*class*

```python
class Applicative(Functor, ABCDispatch)
```

Bases: `apfel.core.monad.Functor`, `apfel.core.dispatch.ABCDispatch`

```python
class Applicative[T](Functor):
    pure
    apply
```

An [applicative functor](https://en.wikipedia.org/wiki/Applicative_functor) is a functor
extended with the ability to apply an effectful function to its inner value(s).

To implement an `Applicative`, you need to implement at least the `pure` and `apply` methods.

See [:haskell `Applicative`](https://wiki.haskell.org/Applicative) for more information.

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/core/monad/__init__.py#L113-L173)

### apfel.core.monad.Applicative.__matmul__

*method* · *classmethod*

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

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/core/monad/__init__.py#L15-L16)

### apfel.core.monad.Applicative.apply

*method* · *abstract*

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

```python
def apply[F, R](self, func: F) -> Self[R]
    where F: Self[Callable[[T], R]]
```

Applies a function wrapped inside the applicative structure to the inner value(s) of this applicative.

**Parameters**

- `func` (`Applicative[Callable[[T], R]]`) — The function to apply, wrapped within the applicative structure.

**Returns**

- (`Applicative[R]`) — A new instance of the applicative with the transformed inner value(s).

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/core/monad/__init__.py#L147-L163)

### apfel.core.monad.Applicative.map

*method*

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

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/core/monad/__init__.py#L165-L173)

### apfel.core.monad.Applicative.pure

*method* · *abstract* · *classmethod*

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

```python
def pure(cls, value: T, /) -> Self[T]
```

Wrap a value into the applicative structure.

**Parameters**

- `value` (`T`) — The value to wrap.

**Returns**

- (`Self`) — A new instance of the applicative with the value wrapped.

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/core/monad/__init__.py#L129-L145)

## apfel.core.monad.Functor

*class*

```python
class Functor(ABCDispatch)
```

Bases: `apfel.core.dispatch.ABCDispatch`

```python
class Functor[T](ABC):
    map
```

A [functor](https://en.wikipedia.org/wiki/Functor) is a type that can apply
a function to its inner value(s) without changing its structure.

To implement a `Functor`, you need to implement at least the `map` method.

See [:haskell `Functor`](https://wiki.haskell.org/Functor) for more information.

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/core/monad/__init__.py#L68-L110)

### apfel.core.monad.Functor.__xor__

*method*

```python
def __xor__(func: Callable[[T], R], /) -> Functor[R]
```

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/core/monad/__init__.py#L9-L9)

### apfel.core.monad.Functor.map

*method* · *abstract*

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

```python
def map[F, R](self, func: F, /) -> Self[R]
    where F: Callable[[T], R]
```

Apply a function to the inner value(s) of the functor, returning a new
instance of the functor.
This corresponds to the [:haskell `fmap`](https://hackage.haskell.org/package/base/docs/Prelude.html#v:fmap) in Haskell.

Built-in [:python `map`](https://docs.python.org/3/library/functions.html#map) function
returns an iterator, not a new instance of the functor.

```python
add = lambda x: x + 1
Functor.map([1, 2, 3], add) # [2, 3, 4]
map([1, 2, 3], add)         # <map object at ...>
```

**Parameters**

- `func` (`Callable[[T], R]`) — The function to apply.

**Returns**

- (`Functor[R]`) — A new instance of the functor with transformed inner value(s).

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/core/monad/__init__.py#L83-L110)

## apfel.core.monad.Monad

*class*

```python
class Monad(Applicative, ABCDispatch)
```

Bases: `apfel.core.monad.Applicative`, `apfel.core.dispatch.ABCDispatch`

```python
class Monad[T](Applicative):
    bind
    (Applicative.pure)
```

A [monad](https://en.wikipedia.org/wiki/Monad_(functional_programming)) is an applicative
functor extended with the ability to reuse results of previous computations and chain
effectful computations together.

To implement a `Monad`, you need to implement at least the `bind` method, and
the [`pure`][apfel.core.monad.Applicative.pure] method from `Applicative`.

See [:haskell `Monad`](https://wiki.haskell.org/Monad) for more information.

> **Note**
>
> `return` is a reserved keyword in Python, and Haskell [:haskell `return`](https://hackage.haskell.org/package/base/docs/Prelude.html#v:return) is a historical mistake that is now
> pointing to [:haskell `pure`](https://hackage.haskell.org/package/base/docs/Prelude.html#v:pure).

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/core/monad/__init__.py#L176-L243)

### apfel.core.monad.Monad.apply

*method*

```python
def apply(func: Applicative[Callable[[T], R]], /) -> Monad[R]
```

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

### apfel.core.monad.Monad.bind

*method* · *abstract*

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

```python
def bind[F, R](self, func: F) -> Self[R]
    where F: Callable[[T], Self[R]]
```

Chain a new monadic computation to the current one.

The argument `func` maps a pure value of the monad's inner type to the monadic value.
`bind` chains this computation to the one it represents.
If its computation fails, the following computations will not be executed.

The function `func` is called a [Kleisli arrow](https://en.wikipedia.org/wiki/Kleisli_category).
This `bind` operation has other names in different programming languages.
For example, in [:rust `Option`](https://doc.rust-lang.org/std/option/enum.Option.html) monad, it is called [:rust `and_then`](https://doc.rust-lang.org/std/option/enum.Option.html#method.and_then).

**Parameters**

- `func` (`Callable[[T], Monad[R]]`) — The function that returns a new monadic computation.

**Returns**

- (`Monad[R]`) — A new instance of the monad with the result of the chained computation.

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/core/monad/__init__.py#L198-L222)

### apfel.core.monad.Monad.map

*method*

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

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/core/monad/__init__.py#L236-L243)

### apfel.core.monad.Monad.pure

*method* · *classmethod*

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

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/core/monad/__init__.py#L27-L29)
