Functional-style Pattern Matching for Python
This library is intended to provide facility in Python to bind together several callables to a single callable object that will dispatch the correct function by predetermined rules.
For example:
@guard(Any.of(0, 1))
def fibonacci(n):
return 1
@guard(Any(int))
def fibonacci(n):
return fibonacci(n - 1) + fibonacci(n - 2)
>>> fibonacci(3)
3
Turns any method of function into a guarded one.
The function decorated by guard
will only be invoked if it's arguments
match the rules provided to guard
.
If several functions in same scope use the same name and have been decorated
by guard
, the resulting function will check all previously decorated
functions (including the current one) for a match.
As a general rule, guard
will match positional arguments to positional arguments
and keyword arguments to keyword arguments. Exceptional rules can be made
to match *args
and **kwards
.
guard(1, "Hello", 3.1415, True)
will match if invoked with the arguments 1, "Hello", 3.1415, True
.
Literal matching will try to match any object that is not of type type
or is not
callable so take caution when using objects that are comparable only by their
id(x)
result.
guard
can use callables that will be invoked on the argument to determine
if it can be passed to the function. The test function must accept one argument
and return True if argument can be passed to the decorated function or False otherwise.
The special object Any
, when used as an argument to guard
will match any
value. Any(t)
for type t
will match any object which is is an instance or
subclass of type t
.
Meant for use in literals, where any of the literals given as arguments to Any.of
is a valid match.
Any.has("attr1", "attr2")
will only match objects o
for which hasattr(o, "attr1")
and hasattr(o, "attr2")
is true.
Any.has(attr1=int, attr2=3)
will only match objects o
for which there exists
attributes "attr1" and "attr2" and the attached rules apply recursively, that is:
o.attr1
is of type int
and o.attr2 == 2
Will match any string that matches the supplied regular expression object or the regular expression compiled from string.
Any.args(*rules)
, when given as the last positional argument will match
any extra positional arguments according to the provided rules. Arguments
must match at least one rule to be valid.
Any.kwargs(key_rule, *value_rules)
will match any extra keyword arguments
if the can match key_rule
and at least one of value_rules
.
TBD We would like to provide rules for matching collections recursively such as mapping and iterable types.
Other possibles goals for this project are:
- Support object, mapping and iterable the construction.
- Export to other programming languages (such as Javascript)