either monad

final class pythonic_fp.fptools.either.Either

Bases: Generic

left biased either monad

Data structure semantically containing either a “left” value or a “right” value, but not both.

  • immutable, hashable when contents are hashable

  • Left values is intended for “expected” results.

  • Right value gives information on the “unexpected” perhaps “exceptional” result.

  • left and right values can be the same or different types

  • in a boolean context

    • left values are truthy

    • right values are falsy

Tip

Happy path without exceptions.

Instead of catching an exception whenever the “happy path” fails, deal with or propagate right values.

Tip

Avoid explicitly importing values LEFT and RIGHT by using the static Either.left and Either.right static methods.

  • left_either: Either[int, str] = Either.left(42)

  • right_either: Either[int, str] = Either.right(‘Not forty-two’)

__init__(value: L, side: T_Bool) → None
__init__(value: R, side: F_Bool) → None

init

Initialize Either instance as a left or a right Either.

param value:

The value contained in the Either.

param side:

Determines whether to produce a “left” or a “right” Either.

type side:

TF_Bool

__hash__() → int

hash

returns:

The integer hash for the Either instance.

raises TypeError:

When contained value is not hashable.

Note

If contained value hashable, use its hash value in the hash calculation, otherwise the Either will be unhashable.

  • should be safe, the Either holds a reference to its value

  • only calculates its hash value when necessary

  • if contained value unhashable, Either will be unhashable

Tip

Use Either instances as dict keys or set members only when both left and right value types are hashable types.

__eq__(other: object) → bool

equality comparison

Compare Either to another object. Compare first by identity, then value.

Note

Pythonic choice was made to allow left or right Either monads to compare as equal if they have different right or left “phantom” types respectively.

  • Allows for more flexible equality checking at the expense of not flagging possible type or name mismatches.

  • Flagging such a type mismatch would require a Liskov Substitution Principle violation.

param other:

The object to be compared.

returns:

True only if other is a Either of the same side containing objects which compare as equal.

__getstate__() → dict[str, object]

getstate

Don’t carry the hash value across pickling and spawn-based multiprocessing (the default on Windows and Mac-OS).

__setstate__(state: dict[str, object]) → None

setstate

Don’t carry the hash value across pickling and spawn-based multiprocessing (the default on Windows and Mac-OS).

__bool__() → bool

bool

  • left Either instances are truthy

  • right Either instances are falsy

returns:

True if Either is a left, False if a right.

__len__() → int

len

An Either always contains just one value.

returns:

1

__iter__() → Iterator

iter

Yield the contained value if Either is a left.

yields:

The contained value if a left.

__repr__() → str

representation string

returns:

A string to reproduce the Either.

Note

Return the strings

  • ‘Either(repr_value, LEFT)’ if a left

  • ‘Either(repr_value, RIGHT)’ if if a right

Where repr_value = repr(value).

__str__() → str

user string

returns:

A string meaningful to an end user.

Note

Return the strings

  • ‘Either(str_value)’ when a left

  • ‘Either(str_value, RIGHT)’ when a right

Where str_value = str(value).

get() → L

get

Get value if a left.

returns:

The value if a left.

raises ValueError:

If not a left.

Warning

Unsafe method get will raise ValueError() if the Either is a right.

Tip

Best practice is to first check the Either in a boolean context.

get_left() → MayBe

get left

Get the value if a left.

returns:

MayBe wrapping a left value.

rtype:

MayBe[L]

get_right() → MayBe

get right

Get the value if a right.

returns:

MayBe wrapping a right value.

rtype:

MayBe[R]

map_right(f: Callable[[R], V]) → Either

map right

Map the function f over the contents of a right Either.

param f:

A function to map a right value.

returns:

A new Either instance if a right, otherwise itself.

map(f: Callable[[L], U]) → Either

map

Map function f over the Either.

param f:

Mapping function.

returns:

A new Either instance if a left, otherwise itself.

map_except(f: Callable[[L], U], fallback_right: R) → Either

map_except

Map function f over the Either with right fallback upon exception.

param f:

Mapping function.

param fallback_right:

Fallback value if exception thrown.

returns:

New left instance if successfully mapped, a propagated right, or a new right when an exception is thrown.

Note

Swallows exceptions of types

  • LookupError

  • ValueError

  • ArithmeticError

  • RuntimeError

Does not attempt to stop exceptions

  • TypeError

  • AttributeError

  • KeyboardInterrupt

bind(f: Callable[[L], Either]) → Either

bind

Flatmap function f over a left value. Propagate right values.

param f:

Function to bind.

returns:

A new Either if a left, itself if a right.

bind_except(f: Callable[[L], Either], fallback_right: R) → Either

bind_except

Flatmap function f over the Either, with fallback upon exception. Propagate right values.

param f:

Function to bind over contained values.

param fallback_right:

Fallback value if exception thrown.

returns:

A successfully bound left, a propagated right, or a right with the fallback value.

Note

Swallows exceptions of types

  • LookupError

  • ValueError

  • ArithmeticError

  • RuntimeError

Does not attempt to stop exceptions

  • TypeError

  • AttributeError

  • KeyboardInterrupt

static left(value: U) → Either

Either.left

Helper static method to explicitly construct a left Either.

param value:

The left value to use when constructing the Either.

returns:

A left Either

static right(value: V) → Either

Either.right

Helper static method to explicitly construct a left Either.

param value:

The left value to use when constructing the Either.

returns:

A right Either

static sequence(iterable_either_uv: Iterable[Either]) → Either[Iterable, V]

Either.sequence

Iterable[Either[U, V]] -> Either[Iterable[U], V]

If all Either are lefts, then return an Either of an Iterable of contained left values. Otherwise return a right Either containing the first right encountered.

param sequence_either_uv:

An Iterable of Either[U, V] values.

returns:

A left Either containing an Iterable of all the left values if none are right Either values, otherwise a right Either containing the first right value.

Note

A sequenced empty Iterable[Either[U, V]] would produce a MayBe of an empty Iterable, not an empty MayBe.

pythonic_fp.fptools.either.LEFT: Final[T_Bool] = T_Bool()

LEFT

var LEFT:

The left Either singleton flag.

pythonic_fp.fptools.either.RIGHT: Final[F_Bool] = F_Bool()

RIGHT

var RIGHT:

The right Either singleton flag