Skip to content

Instantly share code, notes, and snippets.

@kalebo
Created November 20, 2019 21:19
Show Gist options
  • Save kalebo/65642ac3d9326a6916bb1be7334cc353 to your computer and use it in GitHub Desktop.
Save kalebo/65642ac3d9326a6916bb1be7334cc353 to your computer and use it in GitHub Desktop.
Result monad for Python
class Result(metaclass=ABCMeta): # abstract base class
'''A result monad whose interface is patterned after that of Rust's std::Result<T, E> '''
def is_ok(self) -> bool: return NotImplemented
def unwrap_or_else(self, func): return NotImplemented
def unwrap_or(self, val): return NotImplemented
def then(self, f): return NotImplemented # techincally this breaks the monad rules because f might be a functor (A->Result(B)) or it could be just a function (A->B)
class Error(Result):
def __init__(self, err):
self._err = err
def __repr__(self):
return f"Error: {self._err}"
def is_ok(self):
return False
def unwrap_or_else(self, f):
return f(self._err)
def unwrap_or(self, v):
return v
def then(self, _):
return Error(self._err)
class Ok(Result):
def __init__(self, val):
self._val = val
def __repr__(self):
return f"Ok: {self._val}"
def is_ok(self):
return True
def unwrap_or_else(self, _):
return self._val
def unwrap_or(self, _):
return self._val
def then(self, f):
return f(self._val)
def wrap_in_result(f):
if inspect.iscoroutinefunction(f): # this idea for handling async functions came from https://github.com/dry-python/returns
async def decorator(*args, **kwargs):
try:
return Ok(await f(*args, **kwargs))
except Exception as e:
return Error(e)
else:
def decorator(*args, **kwargs):
try:
return Ok(f(*args, **kwargs))
except Exception as e:
return Error(e)
return decorator
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment