Skip to content

Instantly share code, notes, and snippets.

@nuttycom
Last active August 19, 2016 22:22
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nuttycom/9aa9aada69e3c2dcda512ad9a9cde5ab to your computer and use it in GitHub Desktop.
Save nuttycom/9aa9aada69e3c2dcda512ad9a9cde5ab to your computer and use it in GitHub Desktop.
Example of encoding a sum type via catamorphism in Python
Python 3.5.2 |Anaconda custom (64-bit)| (default, Jul 2 2016, 17:53:06)
[GCC 4.4.7 20120313 (Red Hat 4.4.7-1)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import cata
>>> p = cata.DurationPeriod('a', 1)
>>> str(p)
'end_date: a, duration: 1'
>>> q = cata.DatePeriod('a', 'b')
>>> str(q)
'end_date: a, start_date: b'
>>>
# This encodes a simple sum type of two constructors; in Haskell this would be:
# data Period = DurationPeriod { endDate :: Date, duration :: Int }
# | DatePeriod { endDate :: Date, startDate :: Date }
class Period:
def __str__(self):
return self.match(
if_duration = lambda end_date, duration: "end_date: {0}, duration: {1}".format(str(end_date), str(duration)),
if_date = lambda end_date, start_date: "end_date: {0}, start_date: {1}".format(str(end_date), str(start_date)))
class DurationPeriod(Period):
def __init__(self, end_date, duration):
self.end_date = end_date
self.duration = duration
def match(self, if_duration, if_date):
return if_duration(self.end_date, self.duration)
class DatePeriod(Period):
def __init__(self, end_date, start_date):
self.end_date = end_date
self.start_date = start_date
def match(self, if_duration, if_date):
return if_date(self.end_date, self.start_date)
@nuttycom
Copy link
Author

The reason that I use classes here is really to provide the user with the ability to use named arguments in the call to 'match'; while it's possible to encode these types just with lambdas, you then don't get this convenience (or the .match invocation, which I think is helpful to the reader). Also, encapsulating the alternatives as subclasses gives us the ability to define str, eq, hash, etc. in the base class, which allows us to fit in a bit better with the rest of the Python world.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment