Monadic API

Monad

class monadic.Monad

Monad interface.

This is an abstract base class for monads. Monads are wrapper types that allow for chaining operations together.

Subclasses of this class must implement two methods:

  • unit (a class method)

    This method is a constructor that wraps a single value

  • bind (an instance method)

    This method takes a function that maps a value to a monad and returns a monad of the same type.

The interface is somewhat abstract. See monadic.option.Option as an example.

apply(f: Monad[Callable[[T], U]]) Monad[U]

Apply a monadic function to a monad.

This method can be overridden to provide a more efficient or alternative implementation.

Parameters:

f (Monad[Callable[[T], U]]) – A monadic function.

Returns:

The result of applying the monadic function to the wrapped value.

Return type:

Monad[U]

abstract bind(f: Callable[[T], Monad[U]]) Monad[U]

Chain a function that maps a value to a monad.

Parameters:

f (Callable[[T], Monad[U]]) – A function that maps a value to a monad.

Returns:

The result of applying the function to the wrapped value.

Return type:

Monad[U]

map(f: Callable[[T], U]) Monad[U]

Map a function over a monad.

This method can be overridden to provide a more efficient or alternative implementation.

Parameters:

f (Callable[[T], U]) – A function.

Returns:

The result of applying the function to the wrapped value.

Return type:

Monad[U]

abstract classmethod unit(value: U) Monad[U]

Wrap a value in the monad class.

Parameters:

value (U) – The value to wrap.

Returns:

The wrapped value.

Return type:

Monad[U]

Maybe

Maybe monads are a class of monads that represent values that may or may not be present. Monadic exposes two Maybe monads, Option and Result. Option represents a value that may or may not be present, while Result represents the result of an operation that may or may not have succeeded. The main difference between the two is that Option carries no information about why a value may not be present, while Result can carry an error message explaining why an operation may have failed.

class monadic.Maybe

Maybe monad interface.

Base class for monads that represent a value that may or may not exist. Subclasses must implement the following methods:

  • unit (a class method)

    This method is a constructor that wraps a single valid value

  • bind (an instance method)

    How to apply a function to a value that may or may not exist.

  • unwrap (an instance method)

    Retrieve the wrapped value. If the value does not exist, raise an UnwrapError

  • __bool__ (an instance method)

    Return whether the value exists.

default(value: U) Maybe[T] | Maybe[U]

Return a default value if the value does not exist.

If the value exists, return the wrapped value; otherwise, return the wrapped default value.

Parameters:

value (U) – The default value.

Returns:

The wrapped value or the wrapped default value.

Return type:

Union[Maybe[T], Maybe[U]]

abstract classmethod unit(value: U) Maybe[U]

Wrap a value in the monad class.

Parameters:

value (U) – The value to wrap.

Returns:

The wrapped value.

Return type:

Monad[U]

abstract unwrap() T

Retrieve the wrapped value.

Raises:

UnwrapError – If the value does not exist.

Returns:

The wrapped value.

Return type:

T

Option

class monadic.Option

Bases: Maybe[T], ABC

Monadic type representing a value that may or may not exist.

This class is a subclass of Maybe that implements the Monad interface. It is a wrapper type that represents a value that may or may not exist. It has two subclasses: - Some - Nothing

apply(f: Option[Callable[[T], U]]) Option[U]

Apply a function wrapped in an Option.

If self and f are both Some instances, apply the function to the wrapped value and wrap in a Some. Otherwise, return Nothing.

Parameters:

f (Option[Callable[[T], U]]) – A function wrapped in an Option.

Returns:

The result of applying the function to the wrapped value.

Return type:

Option[U]

abstract bind(f: Callable[[T], Option[U]]) Option[U]

Chain a function that maps a value to an Option.

If self is a Some, apply the function to the wrapped value. Otherwise (self is a Nothing), return self.

Parameters:

f (Callable[[T], Option[U]]) – A function that maps a value to an Option.

Returns:

The result of applying the function to the wrapped value.

Return type:

Option[U]

abstract map(f: Callable[[T], U]) Option[U]

Map a function over the wrapped value.

If self is a Some, apply the function to the wrapped value and wrap in a Some. Otherwise (self is a Nothing), return Nothing.

Parameters:

f (Callable[[T], U]) – A function that maps a value to another value.

Returns:

The result of applying the function to the wrapped value.

Return type:

Option[U]

classmethod unit(value: T) Some[T]

Wrap a value in a Some instance.

Parameters:

value (T) – The value to wrap.

Returns:

The wrapped value.

Return type:

Some[T]

Some

class monadic.Some(value: T)

Bases: Option[T]

Option type representing a value that exists.

This class is a subclass of Option that represents a value that exists. It has a value attribute that contains the wrapped value. Some instances are truthy.

Nothing

class monadic.Nothing

Bases: Option

Option type representing a value that does not exist.

This class is a subclass of Option that represents a value that does not exist. Nothing instances are falsy.

Result

class monadic.Result

Bases: Maybe[T], ABC

Monadic type representing the result of a computation that may fail.

This class is a subclass of Maybe that implements the Monad interface. It is a wrapper type that represents the result of a computation that may fail. It has two subclasses: - Ok - Error

apply(f: Result[Callable[[T], U]]) Result[U]

Apply a function wrapped in an Result.

If self and f are both Ok instances, apply the function to the wrapped value and wrap in an Ok. Otherwise, return self.

If an exception is raised while applying the function, return an Error wrapping the exception.

Parameters:

f (Result[Callable[[T], U]]) – The function to apply to the wrapped value

static attempt(_Result__f: Callable[[...], T], _Result__catch: Type[Exception] | Tuple[Type[Exception], ...], *args, **kwargs) Result[T]

Attempt to call a function that may raise an exception.

If the function raises an exception, return an Error

Parameters:
  • __f (Callable[..., T]) – The function to call

  • __catch (Union[Type[Exception], Tuple[Type[Exception], ...]]) – The types of exceptions to catch

  • *args – Positional arguments to pass to the function

  • **kwargs – Keyword arguments to pass to the function

abstract bind(f: Callable[[T], Result[U]]) Result[U]

Chain a function that maps a value to a Result.

If self is an Ok, apply the function to the wrapped value. Otherwise (self is an Error), return self.

Parameters:

f (Callable[[T], Result[U]]) – The function to apply to the wrapped value

map(f: Callable[[T], U]) Result[U]

Map a function over the wrapped value.

If self is an Ok, apply the function to the wrapped value and wrap in an Ok. Otherwise (self is an Error), return self.

If an exception is raised while applying the function, return an Error wrapping the exception.

Parameters:

f (Callable[[T], U]) – The function to apply to the wrapped value

classmethod unit(value: T) Ok[T]

Wrap a value in an Ok instance.

Ok

class monadic.Ok(value: T)

Bases: Result[T]

Result type representing a successful computation.

This class is a subclass of Result that represents a successful computation. It has a value attribute that contains the wrapped value. Ok instances are truthy.

Error

class monadic.Error(exception: Exception =)

Bases: Result

Result type representing a failed computation.

This class is a subclass of Result that represents a failed computation. It has an exception attribute that contains the exception that was raised. Error instances are falsy.

Iterables

Iterable monads are a class of monads that represent a collection of values that can be iterated over. Monadic exposes three Iterable monads, List, Set, and Dict. These monads each map to their respective Python types, but follow a functional style and are immutable.

class monadic.Iterable

Iterable monad interface.

Base class for monads that represent a collection of values that may be iterated over. Subclasses must implement the following methods:

  • unit (a class method)

    This method is a constructor that wraps a single valid value

  • bind (an instance method)

    How to apply a function to a value that may or may not exist.

  • from_iterable (a class method)

    Wrap an iterable in the monad class.

  • empty (a class method)

    Create an empty monad.

  • __eq__ (an instance method)

    Compare two monads for equality.

monadic.Iterable instances are also Python iterables, so they can be used in for loops and comprehensions.

append(value: U) Iterable[T | U]

Add a value to this iterable.

Parameters:

value (U) – The value to add.

Returns:

A new iterable containing the old contents and the value.

Return type:

Iterable[Union[T, U]]

apply(f: Iterable[Callable[[T], U]]) Iterable[U]

Apply an iterable of functions to an iterable.

Parameters:

f (Iterable[Callable[[T], U]]) – An iterable of functions.

Returns:

The result of applying each function to each value in the iterable and concatenating the results.

Return type:

Iterable[U]

bind(f: Callable[[T], Iterable[U]]) Iterable[U]

Chain a function that maps a value to an Iterable.

Parameters:

f (Callable[[T], Iterable[U]]) – A function that maps a value to an Iterable.

Returns:

The result of applying the function to each value in the Iterable and concatenating the results.

Return type:

Iterable[U]

concat(other: Iterable[U]) Iterable[T | U]

Add the contents of another iterable to this iterable.

Parameters:

other (Iterable[U]) – The iterable to add.

Returns:

A new iterable containing the contents of both iterables.

Return type:

Iterable[Union[T, U]]

classmethod empty() Iterable

Create an empty monad.

filter(f: Callable[[T], bool]) Iterable[T]

Filter the values in this iterable.

Parameters:

f (Callable[[T], bool]) – A function that returns True for values to keep.

Returns:

A new iterable containing only the values that pass the filter.

Return type:

Iterable[T]

fold(f: Callable[[U, T], U], initial: U | None = None) U

Fold the values in this iterable.

Parameters:
  • f (Callable[[U, T], U]) – A function that takes the current value and the next value and returns the new value.

  • initial (Optional[U]) – The initial value to use. If not provided, the first value in the iterable is used.

Returns:

The result of folding the iterable.

Return type:

U

abstract classmethod from_iterable(iterable: Iterable[U]) Iterable[U]

Wrap an iterable in a monad.

Parameters:

iterable (Iterable) – The iterable to wrap.

Returns:

A new monad containing the contents of the iterable.

Return type:

Iterable

map(f: Callable[[T], U]) Iterable[U]

Map a function over an iterable.

Parameters:

f (Callable[[T], U]) – A function to map over the iterable.

Returns:

A new iterable containing the result of applying the function to each value in the iterable.

Return type:

Iterable[U]

take(n: int) Iterable[T]

Take the first n values from this iterable.

Parameters:

n (int) – The number of values to take.

Returns:

A new iterable containing the first n values.

Return type:

Iterable[T]

abstract classmethod unit(value: U) Iterable[U]

Wrap a value in the monad class.

Parameters:

value (U) – The value to wrap.

Returns:

The wrapped value.

Return type:

Iterable[U]

List

class monadic.List(inner: Iterable[T])

Bases: Iterable[T]

A monadic list.

This is a wrapper around the built-in list type that implements the Iterable interface. Following a functional style, it is immutable. To add items to the end of the list, use the append() or concat().

Parameters:

inner (Iterable[T]) – The iterable to wrap as a list.

Examples

>>> from monadic.list import List
>>> List([1, 2, 3]).map(lambda x: x + 1)
List([2, 3, 4])
>>> List([1, 2, 3]).bind(lambda x: List([x, x + 1]))
List([1, 2, 2, 3, 3, 4])
>>> List([1, 2, 3]).apply(List([str, float]))
List(['1', 2.0])
>>> List([1, 2, 3]).concat([4, 5, 6])
List([1, 2, 3, 4, 5, 6])
>>> List([1, 2, 3]).append(4)
List([1, 2, 3, 4])
>>> list(List([1, 2, 3]))
[1, 2, 3]
apply(f: Iterable[Callable[[T], U]]) List[U]

Apply each function in a list to each element of a list.

Parameters:

f (List[Callable[[T], U]]) – A list of functions.

Returns:

A new list containing the results of applying each function to each element of the original list.

Return type:

List[U]

bind(f: Callable[[T], Iterable[U]]) List[U]

Chain a function that maps a value to a List.

Parameters:

f (Callable[[T], List[U]]) – A function that maps a value to a List.

Returns:

The result of applying the function to each element of the list, and concatenating the results.

Return type:

List[U]

map(f: Callable[[T], U]) List[U]

Map a function over a list.

Parameters:

f (Callable[[T], U]) – A function that maps a value to a new value.

Returns:

A new list containing the results of applying the function to each element of the original list.

Return type:

List[U]

zip_apply(f: Iterable[Callable[[T], U]]) List[U]

Apply each function in an iterable to the corresponding element.

Parameters:

f (Iterable[Callable[[T], U]]) – An iterable of functions.

Returns:

A new list containing the results of applying each function to the corresponding element of the original list.

Return type:

List[U]

Set

class monadic.Set(inner: Iterable[T])

Bases: Iterable[T]

A monadic set.

This is a wrapper around the built-in set type that implements the Iterable interface. Following a functional style, it is immutable. To add items to the set, use append() or concat().

Parameters:

inner (Iterable[T]) – The iterable to wrap as a set.

Examples

>>> from monadic.set import Set
>>> Set({1, 2, 3}).map(lambda x: x + 1)
Set({2, 3, 4})
>>> Set({1, 2, 3}).bind(lambda x: Set({x, x + 1}))
Set({1, 2, 3, 4})
>>> Set({1, 2, 3}).apply(Set({str, float}))
Set({1.0, 2.0, 3.0, '2', '1', '3'})
>>> Set({1, 2, 3}).concat({3, 4, 5})
Set({1, 2, 3, 4, 5})
>>> Set({1, 2, 3}).append(4)
Set({1, 2, 3, 4})
>>> list(Set({1, 2, 3}))
[1, 2, 3]
apply(f: Iterable[Callable[[T], U]]) Set[U]

Apply an iterable of functions to a set.

Parameters:

f (Iterable[Callable[[T], U]]) – An iterable of functions.

Returns:

The result of applying each function to each value in the set and concatenating the results.

Return type:

Set[U]

bind(f: Callable[[T], Iterable[U]]) Set[U]

Chain a function that maps a value to an iterable.

Parameters:

f (Callable[[T], Iterable[U]]) – A function that maps a value to an iterable.

Returns:

The result of applying the function to each value in the set and concatenating the results.

Return type:

Set[U]

map(f: Callable[[T], U]) Set[U]

Map a function over a set.

Parameters:

f (Callable[[T], U]) – A function that maps a value to a new value.

Returns:

A new set containing the results of applying the function to each value in the original set.

Return type:

Set[U]

Dict

class monadic.Dict(inner: Iterable[Tuple[K, V]] | Dict[K, V])

Bases: Iterable[Tuple[K, V]]

A monadic dictionary.

This is a wrapper around the built-in dict type that implements the Iterable interface. Following a functional style, it is immutable. To add an item to the dictionary by key, use set().

This class is considered an iterable of tuples, where the first item in the tuple is the key and the second item is the value. This differs from the built-in dict type, which is an iterable of keys. To get the keys of a Dict, use the keys() method. To get the values of a Dict, use the values() method.

Parameters:

inner (Iterable[Tuple[K, V]]) – The iterable of tuples containing the key-value pairs to wrap as a dictionary. Alternatively, a dictionary can be passed in directly.

Examples

>>> from monadic.dict import Dict
>>> Dict({"a": 1, "b": 2, "c": 3}).get("a")
Some(1)
>>> Dict({"a": 1, "b": 2, "c": 3}).get("d")
Nothing()
>>> Dict({"a": 1, "b": 2, "c": 3}).set("d", 4)
Dict({'a': 1, 'b': 2, 'c': 3, 'd': 4})
apply(f: Dict[K, Callable[[Tuple[K, V]], Tuple[K2, V2]]]) Dict[K | K2, V | V2]

Apply a dictionary of functions to a dictionary.

For each key-value pair in the dictionary, if the key is present in the dictionary of functions, the function is applied to the key-value pair and the result is added to the result dictionary. If the key is not present in the dictionary of functions, the key-value pair is ignored.

Parameters:

f (Dict[K, Callable[[Tuple[K, V]], Tuple[K2, V2]]]) – A dictionary of functions.

Returns:

The result of applying the corresponding function to each key-value pair in the dictionary and concatenating the results.

Return type:

Dict[Union[K, K2], Union[V, V2]]

apply_keys(f: Dict[K, Callable[[K], K2]]) Dict[K | K2, V]

Apply a dictionary of functions to the keys of a dictionary.

This method is similar to apply(), but only applies the functions to the keys of the dictionary, leaving the values unchanged.

apply_values(f: Dict[K, Callable[[V], V2]]) Dict[K, V | V2]

Apply a dictionary of functions to the values of a dictionary.

This method is similar to apply(), but only applies the functions to the values of the dictionary, leaving the keys unchanged.

bind(f: Callable[[Tuple[K, V]], Dict[K2, V2]]) Dict[K2, V2]

Chain a function that maps a value to a dictionary.

Parameters:

f (Callable[[Tuple[K, V]], Dict[K2, V2]]) – A function that maps a value to a dictionary.

Returns:

The result of applying the function to each key-value pair in the dictionary and concatenating the results.

Return type:

Dict[K2, V2]

drop(key: K) Dict[K, V]

Remove a key-value pair from a dictionary.

Parameters:

key (K) – The key to remove.

Returns:

A new dictionary containing the old contents without the key-value pair.

Return type:

Dict[K, V]

filter(f: Callable[[Tuple[K, V]], bool]) Dict[K, V]

Filter a dictionary by a predicate.

The predicate is a function that takes a key-value pair and returns a boolean. If the predicate returns True, the key-value pair is included in the result. If the predicate returns False, the key-value pair is excluded from the result.

Parameters:

f (Callable[[Tuple[K, V]], bool]) – A predicate function.

Returns:

A new dictionary containing only the key-value pairs for which the predicate returns True.

Return type:

Dict[K, V]

filter_keys(f: Callable[[K], bool]) Dict[K, V]

Filter a dictionary by a predicate on the keys.

This method is similar to filter(), but only applies the predicate to the keys of the dictionary, ignoring the values.

filter_values(f: Callable[[V], bool]) Dict[K, V]

Filter a dictionary by a predicate on the values.

This method is similar to filter(), but only applies the predicate to the values of the dictionary, ignoring the keys.

get(key: K) Option[V]

Get a value from a dictionary by key.

Parameters:

key (K) – The key to look up in the dictionary.

Returns:

A Some containing the value if the key is present in the dictionary, or Nothing if the key is not present.

Return type:

Option[V]

map(f: Callable[[Tuple[K, V]], Tuple[K2, V2]]) Dict[K2, V2]

Map a function over a dictionary.

Parameters:

f (Callable[[Tuple[K, V]], Tuple[K2, V2]]) – A function that maps a key-value pair to a new key-value pair.

Returns:

A new dictionary containing the results of applying the function to each key-value pair in the original dictionary.

Return type:

Dict[K2, V2]

map_keys(f: Callable[[K], K2]) Dict[K2, V]

Map a function over the keys of a dictionary.

This method is similar to map(), but only applies the function to the keys of the dictionary, leaving the values unchanged.

map_values(f: Callable[[V], V2]) Dict[K, V2]

Map a function over the values of a dictionary.

This method is similar to map(), but only applies the function to the values of the dictionary, leaving the keys unchanged.

set(key: K2, value: V2) Dict[K | K2, V | V2]

Add a key-value pair to a dictionary.

Parameters:
  • key (K2) – The key to add.

  • value (V2) – The value to add.

Returns:

A new dictionary containing the old contents and the new key-value pair.

Return type:

Dict[Union[K, K2], Union[V, V2]]