Skip to content

Instantly share code, notes, and snippets.

@drupol
Created January 8, 2025 19:45
Show Gist options
  • Save drupol/f9aaa67171daa7a9a98d302b43ead977 to your computer and use it in GitHub Desktop.
Save drupol/f9aaa67171daa7a9a98d302b43ead977 to your computer and use it in GitHub Desktop.
My initial view of what a Either and Maybe monads would look like in Python
from typing import Callable, Generic, TypeVar, final
A = TypeVar("A", covariant=True)
B = TypeVar("B", covariant=True)
C = TypeVar("C", covariant=True)
@final
class Either(Generic[A, B]):
class Left:
def __init__(self, value: A) -> None:
self.value: A = value
def __str__(self) -> str:
return f"Left({self.value})"
class Right:
def __init__(self, value: B) -> None:
self.value: B = value
def __str__(self) -> str:
return f"Right({self.value})"
value: Left | Right
def __init__(self, value: Left | Right) -> None:
self.value = value
def __str__(self) -> str:
return str(self.value)
@staticmethod
def from_left(value: A) -> "Either[A, B]":
return Either(Either.Left(value))
@staticmethod
def from_right(value: B) -> "Either[A, B]":
return Either(Either.Right(value))
def eval(self, if_left: Callable, if_right: Callable) -> A | B:
return (
if_left(self.value)
if isinstance(self.value, Either.Left)
else if_right(self.value)
)
def map(self, f: Callable[[B], C]) -> "Either[A, C] | Either[A, B]":
return (
Either.fromRight(f(self.value.value))
if isinstance(self.value, Either.Right)
else self
)
def if_left(self, f: Callable[[A], C]) -> B | C:
return (
f(self.value.value)
if isinstance(self.value, Either.Left)
else self.value.value
)
def if_right(self, f: Callable[[B], C]) -> A | C:
return (
f(self.value.value)
if isinstance(self.value, Either.Right)
else self.value.value
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment