This library was originally born from a motivation to process sexps in Python. S-expressions (aka sexps) are a concise way to represent structured data that both humans and computers can interpret. A sexp might look like:

See, easy for humans to grasp, right? But what about computers?

Let's examine a family of [currently] related languages: Python, Ruby, C, and Java, but with emphasis on Python. We're going to assume that the sexp has been converted to a Python-style list or tuple already and thus looks like this:

s = ('quote', ('netlist', ('namespace', 'connector', ('main-board', 'J2')), ('namespace', 'fpga', ('main-board', 'U17')), ('net', ('connector', '1'), ('fpga', 'AE12')), ('net', ('connector', '2'), ('fpga', 'AA22')), ('net', ('connector', '3'), ('connector', '4'), ('fpga', 'B32')) ) )

Phew! That's a lot of commas and quotes! Here's how one would normally process this statement in Python:

assert(len(s) == 2 and s[0] == 'quote') netlist = s[1] assert(len(netlist) > 0 and netlist[0] == 'netlist') for item in netlist: assert(len(item) > 0) if item[0] == 'namespace': assert(len(item) == 3) name, components = item[1], item[2] print 'namespace', name, components if item[0] == 'net': assert(len(item) > 1) connections = item[1:] print 'net', for namespace, port in connections: print '%s:%s' % (namespace, port), print

There are several annoying aspects about this code. The first annoying aspect is that the the programmer has to keep checking the size of lists before accessing items in the list. The second annoying thing is that before unpacking a list, the programmer has to be certain what type of list is about to be unpacked. Functional pattern matching solves these annoyances, freeing the programmer's mind to focus on more important things!

Here is an example of what functional pattern matching looks like when it is officially supported by a language:

match s: when ('quote', netlist): match netlist: when ('netlist', *items): for item in items: match item: when ('namespace', name, components): print 'namespace', name, components when ('net', *connections): print 'net', for connection in connections: match connection: when (namespace, port): print '%s:%s' % (namespace, port), print

I'm going to highlight a portion of each code to demonstrate where functional pattern matching really starts to pay off: when multiple cases must be handled. Look more closely at this bit of Python which has more than one case:

... if item[0] == 'namespace': assert(len(item) == 3) name, components = item[1], item[2] ... if item[0] == 'net': assert(len(item) > 1) connections = item[1:] ...

and also look at the pseudo code for these cases:

... match item: when ('namespace', name, components): ... when ('net', *connections): ...

Notice that the comparison, unpacking, and length checking all happen in one statement (the when statement) in the pseudo code. To be fair, the Python code could be compacted a little bit more, but it is still too verbose and the programmer still must worry about indexing and unpacking:

... if len(item) == 3 and item[0] == 'namespace': name, components = item[1], item[2] if len(item) > 1 and item[0] == 'net': connections = item[1:] ...

So far, the pseudo code looks kinda good.

What else could we ask for? How about nested patterns and also conditions. Okay, here they are:

match s: when ('quote', ('netlist', *items)), len(items) > 0: # <- look here!! for item in items: match item: when ('namespace', name, components): print 'namespace', name, components when ('net', *connections): print 'net', for connection in connections: match connection: when (namespace, port): print '%s:%s' % (namespace, port), print

How about less indentation?:

match s: when ('quote', ('netlist', *items)), len(items) > 0: for item in items: match item: when ('namespace', name, components): print 'namespace', name, components when ('net', *connections): print 'net', for connection in connections: match connection: when (namespace, port): print '%s:%s' % (namespace, port), print