Source code for categories.either

from typing import Callable, Generic, Type, TypeVar, Union

from categories import applicative, functor, bifunctor, monad


A = TypeVar('A')
B = TypeVar('B')
E = TypeVar('E')
Etr = TypeVar('Etr', bound='Either')


[docs]class Either(Generic[E, A]): _RIGHT_TYPE = 'Right' # type: str _LEFT_TYPE = 'Left' # type: str def __init__(self, type: str, value: Union[E, A]) -> None: self.type = type self.value = value def __repr__(self) -> str: return '{}({})'.format(self.type, repr(self.value)) def __eq__(self, other) -> bool: if isinstance(other, type(self)): return (self.type == other.type and self.__dict__ == other.__dict__) else: return False
[docs] def match(self, constructor) -> bool: return constructor(self.value).type == self.type
[docs] @classmethod def left(cls: Type, value: E) -> Etr: return cls(cls._LEFT_TYPE, value)
[docs] @classmethod def right(cls: Type, value: A) -> Etr: return cls(cls._RIGHT_TYPE, value)
Left = Either.left # type: Callable[[E], Either[E, A]] Right = Either.right # type: Callable[[A], Either[E, A]] def _fmap(f: Callable[[A], B], x: Either) -> Either[E, B]: if x.match(Right): return Right(f(x.value)) else: return x def _first(f: Callable[[E], B], x: Either) -> Either[B, A]: if x.match(Left): return Left(f(x.value)) else: return x _second = _fmap def _apply(f: Either, x: Either): if f.match(Right) and x.match(Right): return Right(f.value(x.value)) elif f.match(Left): return f elif x.match(Left): return x def _bind(m: Either[E, A], f: Callable) -> Either: """ (>>=) :: Monad m => m a -> (a -> m b) -> m b """ if m.match(Right): return f(m.value) else: return m functor.instance(Either, _fmap) bifunctor.instance(Either, _first, _second) applicative.instance(Either, Right, _apply) monad.instance(Either, Right, _bind)
[docs]def either(f: Callable, g: Callable, x: Either) -> Either: """ Given two functions and an Either object, call the first function on the value in the Either if it's a Left value, otherwise call the second function on the value in the Either. Return the result of the function that's called. :param f: a function that accepts the type packed in ``x`` :param g: a function that accepts the type packed in ``x`` :param x: an Either object :returns: Whatever the functions ``f`` or ``g`` return """ if x.match(Left): return f(x.value) else: return g(x.value)