Skip to content

Instantly share code, notes, and snippets.

@egregius313
Last active August 25, 2017 23:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save egregius313/6cd3fb6c2d45ea8851fa2900c7ddcba0 to your computer and use it in GitHub Desktop.
Save egregius313/6cd3fb6c2d45ea8851fa2900c7ddcba0 to your computer and use it in GitHub Desktop.
Basic implementation of the "Maybe a" types from Haskell in Python
# maybe.py
"""
Basic implementation of Haskell's Data.Maybe module.
The changes in the API are as follows:
- `maybe` is replaced with the `Maybe` class constructor
- `isJust` and `isNothing` are replaced with the builtin `isinstance`
- `listToMaybe` is replaced with the class method `Maybe.from_iterable`
- `maybeToList` is replaced with an implementation of `__iter__`,
so calls to `list()` will work
- `catMaybes` can be replaced with any standard concatenation function.
- `mapMaybe` is `map_maybe`
"""
from collections import namedtuple
__all__ = ('Maybe', 'Just', 'Nothing')
class Maybe(object):
"""
Superclass for the 'Just a' and 'Nothing' types.
"""
__slots__ = ()
def __new__(cls, value=None):
if value is None:
return Nothing()
return Just(value)
@classmethod
def from_iterable(cls, iterable):
for x in iterable:
return cls(x)
else:
return Nothing()
class Just(namedtuple('Just', 'value'), Maybe):
"""
Simple implementation of the `Just a` construct
"""
__slots__ = ()
def __eq__(self, other):
return isinstance(other, Just) and self.value == other.value
class Nothing(namedtuple('Nothing', []), Maybe):
"""
Implementation of the `Nothing` construct.
"""
__slots__ = ()
_instance = None
def __new__(cls):
# Overriding __new__ allows the creation for a singleton constructor
if cls._instance is not None:
cls._instance = tuple.__new__(cls)
return cls._instance
def __eq__(self, other):
return isinstance(other, Nothing)
def map_maybe(f, *iterables):
for x in map(f, *iterables):
if x is None:
continue
elif x is Nothing():
continue
elif isinstance(x, Just):
yield x.value
else:
yield x
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment