1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
|
from abc import abstractmethod
from typing import Callable, TypeVar, Generic
S = TypeVar("S")
R = TypeVar("R")
E = TypeVar("E")
class Either(Generic[S, E]):
@abstractmethod
def bind(self,
func): # type: (Callable[[S], Either[R, E]]) -> Either[R, E]
raise NotImplementedError
@abstractmethod
def __eq__(self, other): # type: (object) -> bool
raise NotImplementedError
def is_error(self): # type: () -> bool
return not self.is_valid()
def is_valid(self): # type: () -> bool
return {Left: False, Right: True}[type(self)]
def error(self): # type: () -> E
if isinstance(self, Left):
return self._error
else:
raise ValueError("Not an error: %s" % self)
def value(self):
if isinstance(self, Right):
return self._value
else:
raise ValueError("Not a value: %s" % self)
class Right(Either[S, E]):
def __init__(self, value): # type: (S) -> None
self._value = value
def bind(self,
func): # type: (Callable[[S], Either[R, E]]) -> Either[R, E]
return func(self._value)
def __eq__(self, other): # type: (object) -> bool
return isinstance(other, Right) and self._value == other._value
def __str__(self): # type: () -> str
return "Right %s" % self._value
class Left(Either[S, E]):
def __init__(self, error): # type: (E) -> None
self._error = error
def bind(self,
func): # type: (Callable[[S], Either[R, E]]) -> Either[R, E]
return Left(self._error)
def __eq__(self, other): # type: (object) -> bool
return isinstance(other, Left) and self._error == other._error
def __str__(self): # type: () -> str
return "Left: %s" % self._error
|