apfel.core.monad
Monadic interfaces that enable structured ways to compose and manipulate computations on a single effectful construction.
The module defines three abstract classes: Functor,
Applicative, and Monad.
Rationale
Monadic abstractions like Functor, Applicative, and Monad 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, 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.
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,
Option is a Monad,
Option.map is its Functor.map,
Option.and_then is its Monad.bind.
Case: list
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.
assert Functor.map(lambda x: x * 2, lambda x: x + 1)(2) == 5API#
Attributes
| Name | Description |
|---|---|
fmap | An alias for Functor.map. |
Classes
| Name | Description |
|---|---|
Applicative | python |
Functor | python |
Monad | python |
fmapattributemodule attribute#
fmap = Functor.mapAn alias for Functor.map.
Applicativeclass#
class Applicative(Functor, ABCDispatch)Bases: Functor, ABCDispatch
class Applicative[T](Functor): pure applyAn 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 Applicative for more information.
__matmul__methodclassmethod#
def __matmul__(value: T, /) -> Selfapplymethodabstract#
def apply(func: Applicative[Callable[[T], R]], /) -> Applicative[R]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
| Name | Type | Description |
|---|---|---|
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).
mapmethod#
def map(func: Callable[[T], R], /) -> Applicative[R]puremethodabstractclassmethod#
def pure(value: T, /) -> Selfdef pure(cls, value: T, /) -> Self[T]Wrap a value into the applicative structure.
Parameters
| Name | Type | Description |
|---|---|---|
value | T | The value to wrap. |
Returns
Self- A new instance of the applicative with the value wrapped.
Functorclass#
class Functor(ABCDispatch)Bases: ABCDispatch
class Functor[T](ABC): mapA 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 Functor for more information.
__xor__method#
def __xor__(func: Callable[[T], R], /) -> Functor[R]mapmethodabstract#
def map(func: Callable[[T], R], /) -> Functor[R]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 fmap in Haskell.
Built-in map function
returns an iterator, not a new instance of the functor.
add = lambda x: x + 1Functor.map([1, 2, 3], add) # [2, 3, 4]map([1, 2, 3], add) # <map object at ...>Parameters
| Name | Type | Description |
|---|---|---|
func | Callable[[T], R] | The function to apply. |
Returns
Functor[R]- A new instance of the functor with transformed inner value(s).
Monadclass#
class Monad(Applicative, ABCDispatch)Bases: Applicative, ABCDispatch
class Monad[T](Applicative): bind (Applicative.pure)A monad 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 method from Applicative.
See Monad for more information.
applymethod#
def apply(func: Applicative[Callable[[T], R]], /) -> Monad[R]bindmethodabstract#
def bind(func: Callable[[T], Monad[R]], /) -> Monad[R]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.
This bind operation has other names in different programming languages.
For example, in Option monad, it is called and_then.
Parameters
Returns
Monad[R]- A new instance of the monad with the result of the chained computation.
mapmethod#
def map(func: Callable[[T], R], /) -> Monad[R]puremethodclassmethod#
def pure(value: T, /) -> Self