Created
August 24, 2019 20:35
-
-
Save aaronchall/27f5cb71a760da2da99fd69c954e3df4 to your computer and use it in GitHub Desktop.
Python monads, WIP
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 __future__ import annotations | |
from abc import ABC, abstractmethod, abstractproperty | |
from functools import partial | |
def main(): | |
a = 1 | |
b = a + 1 # bind a in b, | |
c = b * 2 # bind b in c, etc... | |
d = c ** 3 | |
print(d) | |
em = EagerMonad(1) # not | |
result = em | add1 | identity | times2 | power3 | to_str | identity | |
print(result.a) | |
#lm = LazyMonad(1) | |
#result2 = lm | identity | add1 | power3 | times2 | |
#print(result2().a) | |
def add1(a: object) -> Monad: | |
b = a + 1 | |
return EagerMonad(b) | |
def times2(a: object) -> Monad: | |
b = a * 2 | |
return EagerMonad(b) | |
def power3(a: object) -> Monad: | |
b = a ** 3 | |
return EagerMonad(b) | |
def to_str(a: object) -> Monad: | |
b = str(a) | |
return EagerMonad(b) | |
def identity(b) -> Monad: | |
"""monadic identity function""" | |
return EagerMonad(b) | |
class Monad(ABC): | |
@abstractproperty | |
def a(self): | |
raise AttributeError('a is not implemented for this AbstractMonad') | |
@abstractmethod | |
def __init__(self, a): | |
self.a = a | |
@abstractmethod | |
def bind(self: Monad, function: MonadicFunction) -> Monad: | |
"""given a unary (i.e. a monadic) function that takes a single argument, `a` | |
and returns a monad (containing potentially another type), | |
return the result of passing `a` to that function | |
""" | |
return function(self.a) | |
def __or__(self, fn): | |
"""allows `Monad(a) | f | g | h` ...""" | |
return self.bind(fn) | |
class EagerMonad(Monad): | |
__slots__ = 'a' | |
def __init__(self, a): | |
self.a = a | |
def bind(self, function): | |
return function(self.a) | |
class LazyMonad(Monad): | |
__slots__ = 'a', 'thunk' | |
def __init__(self, a): | |
self.a = a | |
def bind(self, function): | |
self.thunk = partial(function, self.a) | |
def __call__(self): | |
return self.thunk() | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment