Last active
June 22, 2022 19:02
-
-
Save juliobetta/91309b4fb52e3dbe563b3d4ad02d5fa0 to your computer and use it in GitHub Desktop.
Maybe Monad in Python (naive approach)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from abc import ABC | |
from typing import Callable, TypeVar, Generic | |
T = TypeVar('T') | |
class Maybe(Generic[T], ABC): | |
def __init__(self, value: T | None): | |
self.value = value | |
@staticmethod | |
def of(value: T | None) -> 'Maybe[T]': ... | |
def map(self, f: Callable[[T], 'Maybe[T]']) -> T: ... | |
def flat_map(self, f: Callable[[T], 'Maybe[T]']) -> T | None: ... | |
def __eq__(self, other): | |
return self.value == other.value | |
class Empty(Maybe): | |
def __init__(self): | |
super().__init__(None) | |
@staticmethod | |
def of(value): return Empty() | |
def map(self, f): return self | |
def flat_map(self, f): return None | |
def __repr__(self): return f"Empty()" | |
class Some(Maybe): | |
@staticmethod | |
# def of(value): return Some(value) if value is not None else Empty() | |
def of(value): return Some(value) | |
def map(self, f): return self.flat_map(lambda x: Some.of(f(x))) if self.value is not None else Empty() | |
def flat_map(self, f): return f(self.value) if self.value is not None else None | |
def __repr__(self): return f"Some({self.value})" | |
def main(number: Maybe): | |
value_ = number.map(lambda x: x + 1) | |
f_value = number.flat_map(lambda x: x + 1) | |
m_value = number.map(lambda x: x + 1).map(lambda x: x + 2).map(lambda x: x + 3) | |
matched = None | |
match value_: | |
case Empty(): matched = 'matched: I am Empty' | |
case Some(value=v): matched = f'matched: I am value {v}' | |
return f_value, m_value, matched | |
if __name__ == '__main__': | |
print(main(Some(None))) # -> (None, Empty(), 'matched: I am Empty') | |
print(main(Empty())) # -> (None, Empty(), 'matched: I am Empty') | |
print(main(Some(10))) # -> (11, Some(16), 'matched: I am value 11') | |
def f_(x): return Some(x + 1) | |
def g_(x): return Some(x * 2) | |
# Proving the Monad Laws: | |
# 1. Left identity: | |
assert Some(10).flat_map(f_) == f_(10) | |
# 2. Right identity: | |
assert Some(10).flat_map(Some.of) == Some(10) | |
# 3. Associativity: | |
assert Some(10).flat_map(g_).flat_map(f_) == Some(10).flat_map(lambda x: g_(x).flat_map(f_)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment