Module grscheller.fp.woException
Functional data types to use in lieu of exceptions.
Functions
def mb_to_xor(m: MB[_T], right: _R) ‑> XOR[_T, _R]
-
Convert a MB to an XOR.
def xor_to_mb(e: XOR[_T, _S]) ‑> MB[_T]
-
Convert an XOR to a MB.
Classes
class MB (value: _T | Nothing = Nothing())
-
Class representing a potentially missing value.
- where MB(value) contains a possible value of type _T
- MB( ) semantically represent a "Nothing"
- implementation wise MB( ) contains a nothing: Nothing
- therefore nothing = Nothing(), as a value, cannot be put into a MB
- immutable, a MB does not change after being created
- immutable semantics, map and flatMap produce new instances
Expand source code
class MB(Generic[_T]): """Class representing a potentially missing value. * where MB(value) contains a possible value of type _T * MB( ) semantically represent a "Nothing" * implementation wise MB( ) contains a nothing: Nothing * therefore nothing = Nothing(), as a value, cannot be put into a MB * immutable, a MB does not change after being created * immutable semantics, map and flatMap produce new instances """ __slots__ = '_value', def __init__(self, value: _T|Nothing=Nothing()) -> None: self._value = value def __bool__(self) -> bool: return self._value is not Nothing() def __iter__(self) -> Iterator[_T]: if self: yield self._value # type: ignore # will never yield nothing def __repr__(self) -> str: if self: return 'MB(' + repr(self._value) + ')' else: return 'MB()' def __len__(self) -> int: return (1 if self else 0) def __eq__(self, other: object) -> bool: if not isinstance(other, type(self)): return False return self._value == other._value def get(self, alt: _T|Nothing=Nothing()) -> _T: """Get non-existent contents * if given, return an alternate value of type _T * otherwise, raises ValueError * never returns nothing = Nothing() """ if self: return self._value # type: ignore # will never return nothing else: if alt is Nothing(): raise ValueError('Alternate return type not provided.') else: return alt # type: ignore def map(self, f: Callable[[_T], _S|Nothing]) -> MB[_S]: """Map MB function f over the 0 elements of this data structure.""" return (MB(f(self._value)) if self else MB()) # type: ignore def flatmap(self, f: Callable[[_T], MB[_S]]) -> MB[_S]: """Map MB with function f and flatten.""" return (f(self._value) if self else MB()) # type: ignore
Ancestors
- typing.Generic
Methods
def flatmap(self, f: Callable[[_T], MB[_S]]) ‑> MB[_S]
-
Map MB with function f and flatten.
def get(self, alt: _T | Nothing = Nothing()) ‑> _T
-
Get non-existent contents
- if given, return an alternate value of type _T
- otherwise, raises ValueError
- never returns nothing = Nothing()
def map(self, f: Callable[[_T], _S | Nothing]) ‑> MB[_S]
-
Map MB function f over the 0 elements of this data structure.
class XOR (potential_left: _L | Nothing, default_right: _R)
-
Class that either contains a "left" value or "right" value, but not both.
- implements a left biased Either Monad
- semantically containing 1 of 2 possible types of values
- XOR(left: _L, right: _R) produces "left" value
- XOR(nothing, right: _R) produces a "right" value
- therefore nothing: Nothing as a value cannot be stored as a "left"
- in a Boolean context, returns True if a "left", False if a "right"
- immutable, an XOR does not change after being created
- immutable semantics, map & flatMap return new instances
Expand source code
class XOR(Generic[_L, _R]): """Class that either contains a "left" value or "right" value, but not both. * implements a left biased Either Monad * semantically containing 1 of 2 possible types of values * XOR(left: _L, right: _R) produces "left" value * XOR(nothing, right: _R) produces a "right" value * therefore nothing: Nothing as a value cannot be stored as a "left" * in a Boolean context, returns True if a "left", False if a "right" * immutable, an XOR does not change after being created * immutable semantics, map & flatMap return new instances """ __slots__ = '_left', '_right' def __init__(self, potential_left: _L|Nothing, default_right: _R): self._left, self._right = potential_left, default_right def __bool__(self) -> bool: """Predicate to determine if the XOR contains a "left" or a "right". * true if the XOR is a "left" * false if the XOR is a "right" """ return self._left is not Nothing() def __iter__(self) -> Iterator[_L]: """Yields its value if the XOR is a "left".""" if self: yield self._left # type: ignore # will never yield nothing def __repr__(self) -> str: return 'XOR(' + repr(self._left) + ', ' + repr(self._right) + ')' def __str__(self) -> str: if self: return '< ' + str(self._left) + ' | >' else: return '< | ' + str(self._right) + ' >' def __len__(self) -> int: """Semantically, an XOR always contains just one value.""" return 1 def __eq__(self, other: object) -> bool: if not isinstance(other, type(self)): return False if self and other: return self._left == other._left elif not self and not other: return self._right == other._right else: return False def get(self, alt: _L|Nothing=Nothing()) -> _L: """Get value if a Left. * if the XOR is a left, return its value * otherwise, return alt if it is provided * raises ValueError if alternate value needed but not provided """ if self._left is Nothing(): if alt is Nothing(): raise ValueError('Alternate return type needed but not provided.') else: return alt # type: ignore # will never return nothing else: return self._left # type: ignore # will never return nothing def getRight(self, alt: _R|Nothing=Nothing()) -> _R: """Get value if a Right. * if XOR is a right, return its value * otherwise return an alternate value of type _R * raises ValueError if alternate value needed but not provided """ if not self: return self._right else: if alt is Nothing(): raise ValueError('Alternate return type needed but not provided.') else: return alt # type: ignore def getDefaultRight(self) -> _R: """Get value if a "right" or the default "right" value. * if XOR is a right, return its value * otherwise return the left's default right value """ return self._right def map(self, f: Callable[[_L], _S|Nothing], right: _R|Nothing=Nothing()) -> XOR[_S, _R]: """Map over an XOR. * if a "Left" XOR map f and return a "Left" XOR if f successful * otherwise, if f unsuccessful, return "Right" XOR with right not nothing: Nothing * otherwise, if right is nothing, return the default "Right" XOR * if a "Right" return a "Right" XOR with a non-nothing right * otherwise, if right is nothing, propagate new "Right" XOR instance """ nothing = Nothing() if self._left is nothing: if right is nothing: return XOR(nothing, self._right) else: return XOR(nothing, right) # type: ignore else: if right is nothing: return XOR(f(self._left), self._right) # type: ignore else: return XOR(f(self._left), right) # type: ignore def mapRight(self, g: Callable[[_R], _R]) -> XOR[_L, _R]: """Map over a "right" value.""" if self._left is Nothing(): return XOR(Nothing(), g(self._right)) return self def flatMap(self, f: Callable[[_L], XOR[_S, _R]]) -> XOR[_S, _R]: """Map and flatten a Left value, propagate Right values.""" if self._left is Nothing(): return XOR(Nothing(), self._right) else: return f(self._left) # type: ignore
Ancestors
- typing.Generic
Methods
def flatMap(self, f: Callable[[_L], XOR[_S, _R]]) ‑> XOR[_S, _R]
-
Map and flatten a Left value, propagate Right values.
def get(self, alt: _L | Nothing = Nothing()) ‑> _L
-
Get value if a Left.
- if the XOR is a left, return its value
- otherwise, return alt if it is provided
- raises ValueError if alternate value needed but not provided
def getDefaultRight(self) ‑> _R
-
Get value if a "right" or the default "right" value.
- if XOR is a right, return its value
- otherwise return the left's default right value
def getRight(self, alt: _R | Nothing = Nothing()) ‑> _R
-
Get value if a Right.
- if XOR is a right, return its value
- otherwise return an alternate value of type _R
- raises ValueError if alternate value needed but not provided
def map(self, f: Callable[[_L], _S | Nothing], right: _R | Nothing = Nothing()) ‑> XOR[_S, _R]
-
Map over an XOR.
- if a "Left" XOR map f and return a "Left" XOR if f successful
- otherwise, if f unsuccessful, return "Right" XOR with right not nothing: Nothing
- otherwise, if right is nothing, return the default "Right" XOR
- if a "Right" return a "Right" XOR with a non-nothing right
- otherwise, if right is nothing, propagate new "Right" XOR instance
def mapRight(self, g: Callable[[_R], _R]) ‑> XOR[_L, _R]
-
Map over a "right" value.