One of the nicest features of functional programming languages like Haskell and Erlang is pattern matching. An example, from Learn You Some Erlang:
greet(male, Name) ->
io:format("Hello, Mr. ~s!", [Name]);
greet(female, Name) ->
io:format("Hello, Mrs. ~s!", [Name]);
greet(_, Name) ->
io:format("Hello, ~s!", [Name]).
The function body that is called is the one where the pattern matches what is passed in. It’s sort of like overloading functions in C++, but instead of just based on types, it’s much more generic.
I program in Python, and I’ve thought for a while that I could probably implement this in Python. I had a few breakthroughs about how to do it last night, and so inspired in part by other language syntax hacks, like the goto statement and anonymous/ruby blocks I put together a pretty neat prototype and uploaded it to a github gist: https://gist.github.com/1320421.
Here are some examples of what you can do:
from patternmatching import ifmatches, Any, OfType, Where
@ifmatches
def greet(gender=OfType(str), name="Joey"):
print "Joey, whats up man?"
@ifmatches
def greet(gender="male", name=Any):
print "Hello Mr. %s" % name
@ifmatches
def greet(gender="female", name=Any):
print "Hello Ms. %s" % name
@ifmatches
def greet(gender=Any, name=Any):
print "Hello, %s" % name
You can match parameters on four different ways
- by its type with
def fun(a=OfType(str, int)):
- by an exact match
def fun(a=54):
- with any arbitrary predicate
def fun(a=Where(str.isupper)):
- with a “wildcard”
def fun(a=Any):
Known Limitations
- Cannot be called with keyword arguments, due to limitations of python’s function introspection. I might be wrong about this though. I’m sure it’s possible somehow, but I’d rather not do anything like say… tokenize the file myself.
- Does not have data deconstruction like Haskell and Erlang, but I think I know how to do this after consulting with colleague
- You give up the ability to use *args/**kwargs with your function, since the ideas are not especially compatible
- You must specify every argument as a named parameter in the definition. Each clause/def does not need to have consistent naming, at least not yet. In fact, they don’t even need to have the same number of arguments.
Similar Implementations
- Guido did something similar with "multimethods"; the implementation is somewhat similar but it's more like C++; you can only overload based on types, not on arbitrary "matching."
- Ian Bicking wrote patmatch which is roughly the same idea (I found it afterwards) but I don't like it as much; the implementation is longer and it doesn't let you reuse the method's names (each possible match is a different function name and is associated to the original with a decorator). Also it doesn't abuse default parameters but instead uses decorator arguments.