Source code for categories.validation

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

from categories import applicative, functor, bifunctor, semigroup
from categories import sappend


A = TypeVar('A')
B = TypeVar('B')
E = TypeVar('E')
Vn = TypeVar('Vn', bound='Validation')


[docs]class Validation(Generic[E, A]): _SUCCESS_TYPE = 'Success' _FAILURE_TYPE = 'Failure' 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 def match(self, constructor) -> bool: return constructor(self.value).type == self.type @classmethod def failure(cls: Type, value: E) -> Vn: return cls(cls._FAILURE_TYPE, value) @classmethod def success(cls: Type, value: E) -> Vn: return cls(cls._SUCCESS_TYPE, value)
Failure = Validation.failure # type: Callable[[E], Validation[E, A]] Success = Validation.success # type: Callable[[E], Validation[E, A]] def _sappend(a: Validation[E, A], b: Validation[E, A]) -> Validation[E, A]: if a.type == b.type: return Validation(a.type, sappend(a.value, b.value)) elif a.match(Failure): return a else: return b def _fmap(f: Callable[[A], B], x: Validation) -> Validation: if x.match(Failure): return x else: return Success(f(x.value)) def _first(f: Callable, x: Validation) -> Validation: if x.match(Failure): return Failure(f(x.value)) else: return x _second = _fmap def _apply(f: Validation, x: Validation) -> Validation: if f.match(Success) and x.match(Success): return Success(f.value(x.value)) elif f.match(Failure): return f else: return x semigroup.instance(Validation, _sappend) functor.instance(Validation, _fmap) bifunctor.instance(Validation, _first, _second) applicative.instance(Validation, Success, _apply)