- Notifications
You must be signed in to change notification settings - Fork0
full-featured pattern-matching in python, however it's more likely to be dynamic contracts.
License
NotificationsYou must be signed in to change notification settings
Xython/pattern-matching
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
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, checkhttps://zhuanlan.zhihu.com/p/42684997.
The documents have been migrated to README now:
These are all you need to import.
frompattern_matchingimportvar,_,T,t,when,Match,overwrite
@when(var[T==int])# T means the type would be capture.deff(v,type_of_v):print(v,type_of_v)f(1)# => (1, int)
Remark: UsingMatch
is similar towhen/overwrite
:
m=Match(1)res=m.case(var[T==int])ifres: [a,b]=res.getassert [a,b]== [1,int]
If the pattern matched,Match.case
returns aResult
object.
classResult:__slots__='get'def__init__(self,_):self.get=_
Otherwise the return isNone
.
@when(_==1)deff():return12@when(_==2)deff():return0@when(var)deff(arg):returnarg**3f(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.deff(v):print(v)f(1.0)# => 1.0
@when(_)deff():return1f(1)==f("...")==f(1e-3)# => True
classMyList(list):passfromcollectionsimportIterable@when(var[Iterable<=T<=MyList] .when(lambdax:1inx))deff(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(_== [])defsummary():return0@when([var[int],*(_== [])])defsummary(head):returnhead@when([var[int],*var[list]])defsummary(head,tail):returnhead+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)])defdisp(x):print(x)disp(1)# => 1disp('1')# => '1'
classA:passclassB:passclassC(A,B):pass@when(_[(T==A)| (T==B)])defdisp(ty):print(ty)disp(C())# => <class __main__.C>
classA:passclassB:passclassC(A,B):pass@when(_[T!=A])defdisp(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 onpattern_matching.T/t
.
For instance, to avoid subclassing, follow this:
classA:passclassB:passclassC(A,B):pass@overwrite(_[T.when(lambda_:notissubclass(_,A))])defdisp(ty):print(ty)disp(C())# => <class __main__.C># => UnsolvedCase: No entry for args<(<__main__.C object at ...>,)>, kwargs:<{}>
@when(var/2)deff(g):returng(1,2)f(lambdaa,b:a+b)# => 3f(lambdaa,b,c:a+b)# => UnsolvedCase: No entry for args<(<function <lambda> at ...>,)>, kwargs:<{}>classF:defapply(self,arg):returnarg+1@when(var/1)deff2(g):returng(1)f2(lambdaa,b:a+b)# => UnsolvedCase: No entry for args<(<function <lambda> at ...>,)>, kwargs:<{}>f2(F().apply)# => 2