Created
August 21, 2012 07:19
-
-
Save nvanderw/3413049 to your computer and use it in GitHub Desktop.
Typeclass stuff in Python
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
import itertools | |
# Monad instance on a Python iterator, very similar to Haskell's list monad. | |
# In general, Haskell typeclass instances can be regarded as dictionaries which | |
# map the implemented function to its implementation. For a good explanation of | |
# this, see Philip Wadler's "Faith, Evolution, and Programming Languages" | |
# lecture. What this means for us is that we can write a function whose type | |
# signature in Haskell would be: | |
# Monad m => f m | |
# | |
# Where f m is some type parameterized over m, as: | |
# Monad m -> f m | |
# | |
# That is, the instance of monad is passed as a dictionary along with the | |
# function parameterized over the monad. This IterMonad class is an example of | |
# such a dictionary. | |
# | |
# We can see a dynamic type system as having a single type: Dyn. Thus the | |
# category of Python types has a single object and is defined entirely by its | |
# morphisms. | |
class IterMonad(object): | |
# Functor implementation | |
@staticmethod | |
def fmap(f, m): return itertools.imap(f, m) | |
# Monad implementation | |
@staticmethod | |
def inject(a): return [a] | |
@staticmethod | |
def join(m): return itertools.chain.from_iterable(m) | |
# Monoid/MonadPlus implementation | |
mzero = [] | |
@staticmethod | |
def mplus(m, n): | |
return itertools.chain(m, n) | |
# Given a monad instance like above, yields a class object with a couple utility | |
# functions for monads. | |
def getMonadUtils(inst): | |
class MonadUtils(object): | |
@staticmethod | |
def bind(m, f): | |
return inst.join(inst.fmap(f, m)) | |
# mapM, liftM, and all that goodness goes here | |
# Monadic filter example | |
@staticmethod | |
def mfilter(p, m): | |
return MonadUtils.bind(m, lambda a: inst.inject(a) if p(a) else inst.mzero) | |
return MonadUtils | |
# Implementation of IO Monad goes here | |
# Filter out odd elements from [0..] | |
for elem in getMonadUtils(IterMonad).mfilter(lambda n: (n % 2) == 0, itertools.count()): | |
print elem |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
It's pretty trivial to enforce type schema on Python objects. We did this a lot at TiVo. Define a schema in one place, along with a checking function. Then you can require DTOs or more general objects to have certain members that could recursively have types enforced on them. It might be a more pythonic way to do this.