Tail call optimization(TCO) has been removed from this package for following reasons:
- TCO is easy to implement.
- Guaranteeing TCO dynamically in any situations is really expensive.
If you do want to use TCO in Python, check https://zhuanlan.zhihu.com/p/42684997.
The documents have been migrated to README now:
These are all you need to import.
from pattern_matching import var, _, T, t, when, Match, overwrite
@when(var[T == int])
# T means the type would be capture.
def f(v, type_of_v):
print(v, type_of_v)
f(1)
# => (1, int)
Remark: Using Match
is similar to when/overwrite
:
m = Match(1)
res = m.case(var[T == int])
if res:
[a, b] = res.get
assert [a, b] == [1, int]
If the pattern matched, Match.case
returns a Result
object.
class Result:
__slots__ = 'get'
def __init__(self, _):
self.get = _
Otherwise the return is None
.
@when(_ == 1)
def f():
return 12
@when(_ == 2)
def f():
return 0
@when(var)
def f(arg):
return arg ** 3
f(1), f(2), f(3) # => 12, 0, 27
@when(var[t == float])
# the lowercase, "t", which indicates that the type just be matched without capture.
def f(v):
print(v)
f(1.0)
# => 1.0
@when(_)
def f():
return 1
f(1) == f("...") == f(1e-3)
# => True
class MyList(list):
pass
from collections import Iterable
@when(var[Iterable <= T <= MyList]
.when(lambda x: 1 in x)
)
def f(x, T):
return (x, T)
f([1, 2, 3])
# => ([1, 2, 3], list)
f({1, 2, 3})
# => UnsolvedCase: No entry for args<({1, 2, 3},)>, kwargs:<{}>
Overloading functions are introduced through the following simple cases:
@overwrite(_ == [])
def summary():
return 0
@when([var[int], *(_== [])])
def summary(head):
return head
@when([var[int], *var[list]])
def summary(head, tail):
return head summary(tail)
summary([1, 2, 3])
# => 6
Note that above code is definitely useless for it doesn't use tail call optimization.
@when(var[(t == int) | (t == str)])
def disp(x):
print(x)
disp(1) # => 1
disp('1') # => '1'
class A:
pass
class B:
pass
class C(A, B):
pass
@when(_[(T == A) | (T == B)])
def disp(ty):
print(ty)
disp(C()) # => <class __main__.C>
class A:
pass
class B:
pass
class C(A, B):
pass
@when(_[T != A])
def disp(ty):
print(ty)
disp(C()) # => <class __main__.C>
disp(B()) # => <class __main__.B>
disp(A())
# => UnsolvedCase: No entry for args<(<__main__.A object at ...>,)>, kwargs:<{}>
You can apply .when(predicate)
methods on pattern_matching.T/t
.
For instance, to avoid subclassing, follow this:
class A:
pass
class B:
pass
class C(A, B):
pass
@overwrite(_[T.when(lambda _: not issubclass(_, A))])
def disp(ty):
print(ty)
disp(C()) # => <class __main__.C>
# => UnsolvedCase: No entry for args<(<__main__.C object at ...>,)>, kwargs:<{}>
@when(var/2)
def f(g):
return g(1, 2)
f(lambda a, b: a b) # => 3
f(lambda a, b, c: a b)
# => UnsolvedCase: No entry for args<(<function <lambda> at ...>,)>, kwargs:<{}>
class F:
def apply(self, arg):
return arg 1
@when(var/1)
def f2(g):
return g(1)
f2(lambda a, b: a b)
# => UnsolvedCase: No entry for args<(<function <lambda> at ...>,)>, kwargs:<{}>
f2(F().apply) # => 2