<NME> either.py
<BEF> from abc import abstractmethod
from functools import partial

from typing import Callable, TypeVar, Generic

from oslash.typing import Applicative
from oslash.typing import Functor
from oslash.typing import Monad


class Either(Monad, Applicative, Functor, metaclass=ABCMeta):

    @abstractmethod
    def map(self, _) -> "Either":
        return NotImplemented

    @abstractmethod
    def map(self, _: Callable[[TSource], TResult]) -> "Either[TResult, TError]":
        raise NotImplementedError

    @classmethod
    @abstractmethod
    def pure(cls, value: Callable[[TSource], TResult]) -> "Either[Callable[[TSource], TResult], TError]":
        raise NotImplementedError

    @abstractmethod
    def apply(


class Right(Either):
    def __init__(self, value):
        self._get_value = lambda: value

    @abstractmethod
    def bind(self, func: Callable[[TSource], "Either[TResult, TError]"]) -> "Either[TResult, TError]":
        raise NotImplementedError

    @abstractmethod
    def __eq__(self, other) -> bool:
        raise NotImplementedError


class Right(Either[TSource, TError]):

    """Represents a successful computation."""

    def __init__(self, value: TSource) -> None:
        self._value = value

    # Functor Section
    # ===============

    def map(self, mapper: Callable[[TSource], TResult]) -> Either[TResult, TError]:


class Left(Either):
    def apply(self, something: Either) -> Either:
        return Left(self._get_value())


    def apply(
        self: "Right[Callable[[TSource], TResult], TError]", something: "Either[TSource, TError]"
    ) -> "Either[TResult, TError]":
        def mapper(other_value):
            try:
                return self._value(other_value)
            except TypeError:
                return partial(self._value, other_value)

        return something.map(mapper)

    # Monad Section
    # =============

    @classmethod
    def unit(cls, value: TSource) -> "Right[TSource, TError]":
        return Right(value)

    def bind(self, func: Callable[[TSource], Either[TResult, TError]]) -> Either[TResult, TError]:
        return func(self._value)

    # Operator Overloads
    # ==================

    def __eq__(self, other) -> bool:
        return isinstance(other, Right) and self._value == other._value

    def __str__(self) -> str:
        return "Right %s" % self._value


class Left(Either[TSource, TError]):

    """Represents a computation that has failed."""

    def __init__(self, error: TError) -> None:
        self._error = error

    @classmethod
    def pure(cls, value: Callable[[TSource], TResult]) -> Either[Callable[[TSource], TResult], TError]:
        return Right(value)

    def apply(self, something: Either) -> Either:
        return Left(self._error)

    def map(self, mapper: Callable[[TSource], TResult]) -> Either[TResult, TError]:
        return Left(self._error)

    @classmethod
    def unit(cls, value: TSource):
        return Right(value)

    def bind(self, func: Callable[[TSource], Either[TResult, TError]]) -> Either[TResult, TError]:
        return Left(self._error)

    def __eq__(self, other) -> bool:
        return isinstance(other, Left) and self._error == other._error

    def __str__(self) -> str:
        return "Left: %s" % self._error


assert(isinstance(Either, Functor))
assert(isinstance(Either, Applicative))
assert(isinstance(Either, Monad))

assert(isinstance(Right, Functor))
assert(isinstance(Right, Applicative))
assert(isinstance(Right, Monad))

assert(isinstance(Left, Functor))
assert(isinstance(Left, Applicative))
assert(isinstance(Left, Monad))

<MSG> Updated readme and docstrings

<DFF> @@ -10,6 +10,12 @@ from oslash.abc import Monad
 
 class Either(Monad, Applicative, Functor, metaclass=ABCMeta):
 
+    """The Either Monad.
+
+    Represents either a successful computation, or a computation that
+    has failed.
+    """
+
     @abstractmethod
     def map(self, _) -> "Either":
         return NotImplemented
@@ -28,6 +34,9 @@ class Either(Monad, Applicative, Functor, metaclass=ABCMeta):
 
 
 class Right(Either):
+
+    """Represents a successful computation."""
+
     def __init__(self, value):
         self._get_value = lambda: value
 
@@ -54,6 +63,9 @@ class Right(Either):
 
 
 class Left(Either):
+
+    """Represents a computation that has failed."""
+
     def apply(self, something: Either) -> Either:
         return Left(self._get_value())
 

Updated readme and docstrings