Source code for pymonad.maybe

# --------------------------------------------------------
# (c) Copyright 2014, 2020 by Jason DeLaat.
# Licensed under BSD 3-clause licence.
# --------------------------------------------------------
""" Implements the Maybe monad and related functions.

The Maybe monad is used to represent calculations that may or may not
return a value. Alternately, if used as function inputs, Maybe values
can be used to indicate 'optional' inputs, explicitly passing
'Nothing' when no input is required.

When creating Maybe values directly use the 'Just' function or 'Nothing':

Example:
    >>> x = Just(19)
    >>> y = Just('A string')
    >>> z = Nothing

The 'insert' class method is a wrapper around the 'Just' function.

Example:
    >>> x = Maybe.insert(9) # Same as Just(9)
"""
from typing import Any, Callable, Generic, TypeVar

import pymonad.monad

S = TypeVar("S")  # pylint: disable=invalid-name
T = TypeVar("T")  # pylint: disable=invalid-name


[docs]class Maybe(pymonad.monad.Monad, Generic[T]): """ The Maybe monad class. """
[docs] @classmethod def insert(cls, value: T) -> "Maybe[T]": """ See Monad.insert """ return Just(value)
[docs] def amap(self: "Maybe[Callable[[S], T]]", monad_value: "Maybe[S]") -> "Maybe[T]": """ See Monad.amap""" if ( self.is_nothing() or monad_value.is_nothing() ): # pylint: disable=no-else-return return Nothing else: return monad_value.map(self.value)
[docs] def bind( self: "Maybe[S]", kleisli_function: "Callable[[S], Maybe[T]]" ) -> "Maybe[T]": """ See Monad.bind """ if self.monoid is False: # pylint: disable=no-else-return return self else: try: return kleisli_function(self.value) except: # pylint: disable=bare-except return Nothing
[docs] def is_just(self) -> bool: """ Returns True if the monad instance was created with the 'Just' function. """ return self.monoid
[docs] def is_nothing(self) -> bool: """ Returns True if the monad instance is the 'Nothing' value. """ return not self.monoid
[docs] def map(self: "Maybe[S]", function: Callable[[S], T]) -> "Maybe[T]": """ See Monad.map """ if self.is_nothing(): # pylint: disable=no-else-return return self else: try: return Just(function(self.value)) except: # pylint: disable=bare-except return Nothing
def __eq__(self, other): """ Checks equality of Maybe objects. Maybe objects are equal iff: #. They are both Nothing, or #. They are both Just and #. They both contain the same value. """ return self.value == other.value and self.monoid == other.monoid def __repr__(self): return f"Just {self.value}" if self.monoid else "Nothing"
[docs]def Just(value: T) -> Maybe[T]: # pylint: disable=invalid-name """ A Maybe object representing the presence of an optional value. """ return Maybe(value, True)
# A Maybe object representing the absence of an optional value. Nothing: Maybe[Any] = Maybe(None, False) # pylint: disable=invalid-name
[docs]class Option( pymonad.monad.MonadAlias, Maybe[T] ): # MonadAlias must be the first parent class """ An alias for the Maybe monad class. """ def __repr__(self): return f"Some {self.value}" if self.monoid else "Nothing"
[docs]def Some(value: T) -> Option[T]: # pylint: disable=invalid-name """ An Option object representing the presence of an optional value. """ return Option(value, True)