from __future__ import annotations from typing import TypeVar, Generic, Optional, Callable, Any T = TypeVar('T') U = TypeVar('U') class Maybe(Generic[T]): def __init__(self, value: Optional[T] = None): self._value: Optional[T] = value @staticmethod def of(obj: T) -> Maybe[T]: return Maybe(obj) @staticmethod def of_nullable(obj: Optional[T]) -> Maybe[T]: return Maybe(obj) @staticmethod def empty() -> Maybe[U]: return _empty @property def value(self) -> T: value = self._value if not value: raise ValueError('Empty Maybe') else: return value @property def is_present(self) -> bool: return self._value is not None @property def is_empty(self) -> bool: return not self.is_present def map(self, transformer: Callable[[T], U]) -> Maybe[U]: result: Maybe[U] if self.is_present: result = Maybe(transformer(self.value)) else: result = Maybe.empty() return result def filter(self, predicate: Callable[[T], bool]) -> Maybe[T]: return self if self.is_present and predicate(self.value) else Maybe.empty() def flat_map(self, transformer: Callable[[T], Maybe[U]]) -> Maybe[U]: return transformer(self.value) if self.is_present else Maybe.empty() def or_else(self, alt: T) -> T: return self.value if self.is_present else alt def or_else_throw(self, supplier: Callable[[], Exception]) -> T: if self.is_present: return self.value else: raise supplier() def or_else_get(self, supplier: Callable[[], T]) -> Maybe[T]: return self if self.is_present else Maybe.of_nullable(supplier()) def if_present(self, callback: Callable[[T], U]) -> None: if self.is_present: callback(self.value) _empty: Maybe[Any] = Maybe(None)