Xpattern: Pattern Matching with XObject.
xpatternis inspired by hask, pipetools, pampy, and withxpatternyour code will be more readable and graceful!
Let's play now
Each pattern matchline evaluated in the order they appear.
from xpattern import caseof
from xpattern import m
~(caseof(v)
| m(pattern_1) >> action_1
| m(pattern_2) >> action_2
)
caseof is lazy, so you need to add ~ operator to run it!
m is a matcher, if you don't like circular brackets style, you can alse use square brackets style
from xpattern import caseof
from xpattern import m
~(caseof(v)
| m[pattern_1] >> action_1
| m[pattern_2] >> action_2
)
Write a Fibonacci
The operator
_means "match everything"
from xpattern import _
from xpattern import caseof
from xpattern import m
def fibonacci(n):
return ~(caseof(n)
| m(1) >> 1
| m(2) >> 1
| _ >> (lambda x: fibonacci(x - 1) + fibonacci(x - 2))
)
Write a Lisp calculator
from functools import reduce
from xpattern import _
from xpattern import REST
from xpattern import caseof
from xpattern import m
def lisp(exp):
return ~(caseof(exp)
| m(int) >> (lambda x: x)
| m(callable) >> (lambda x: x)
| m(callable, REST) >> (lambda f, rest: f(*map(lisp, rest)))
| m(tuple) >> (lambda t: list(map(lisp, t)))
)
plus = lambda a, b: a + b
minus = lambda a, b: a - b
lisp((plus, 1, 2)) # => 3
lisp((plus, 1 (minus, 4, 2))) # => 3
lisp((reduce, plus, (range, 10))) # => 45
You can match so many things!
~(caseof(x)
| m(3) >> "this matches the number 3"
| m(int) >> "matches any integer"
| m(str, int) >> (lambda a, b: "a tuple (a, b) you can use in a function")
| m(1, 2, _) >> "any list of 3 elements that begins with [1, 2]"
| m({"x", _}) >> "any dict with a key 'x' and any value associated"
| _ >> "anything else"
)
Match dataclass
from dataclasses import dataclass
from xpattern import _
from xpattern import caseof
from xpattern import m
@dataclass
class Point:
x: int
y: int
@dataclass
class Point2:
x: int
y: int
@dataclass
class Line:
p1: Point
p2: Point
@dataclass
class Rect:
l1: Line
l2: Line
~(caseof(Rect(Point(1, 2), Point(3, 4)))
| m(Rect(Point(_, str), Point(_, 4))) >> "first"
| m(Rect(Point(_, int), Point2(_, 4))) >> "second"
| m(Rect(Point(_, int), Point(_, 4))) >> (lambda x, y, z: (x, y, z))
) # => (1, 2, 3)
Match [HEAD, TAIL]
from xpattern import _
from xpattern import HEAD
from xpattern import TAIL
from xpattern import caseof
from xpattern import m
x = [1, 2, 3]
~(caseof(x)
| m(1, TAIL) >> (lambda t: t) # => [2, 3]
)
~(caseof(x)
| m(HEAD, TAIL) >> (lambda h, t: (h, t)) # => [1, [2, 3]]
)
Chain match
from xpattern import _
from xpattern import caseof
from xpattern import m
pet = {"type": "dog", "details": {"age": 3}}
~(caseof(pet)
| m({_: {"age": _}}) >> ~(caseof(X)
| m(int, int) >> (lambda x, y: x + y)
| m(str, int) >> (lambda x, y: y)
)
) # => 3
With Bitwise Operators
from xpattern import _
from xpattern import caseof
from xpattern import m
~(caseof(1)
| (m[2] | m[1]) >> 1
| _ >> "nothing"
) # => 1
~(caseof(11)
| (m[lambda x: x > 1] & m[lambda x: x < 10]) >> "1 < x < 10"
| (m[lambda x: x > 1] & m[lambda x: x < 15]) >> "1 < x < 15"
) # => "1 < x < 15"
~(caseof(6)
| ~m[lambda x: x > 5] >> "x <=5"
| ~m[lambda x: x > 10] >> "x <= 10"
) # => "x <= 10"
More pattern cases
Your can visit repo pampy get more pattern cases,
xpatternis Syntactic Sugar ofpampy
Why name Xpattern, what's X mean?
XmeansXObject!!!
XObjectis a Syntactic Sugar oflambdafunction
from xpattern import X
from xpattern import caseof
from xpattern import m
~(caseof(1)
| m(1) >> X + 1 # => 2
)
~(caseof("apple")
| m(str) >> X.upper() # => "APPLE"
)
~(caseof([1, 2, 3])
| m(1, 2, 3) >> X[2] # => 3
)
~(caseof([1, 2, 3])
| m(1, 2, 3) >> X + [4, 5, 6] # => [1, 2, 3, 4, 5, 6]
)
~(caseof(9)
| m(int) >> X + X ** (X << 2) % 2 / 3 - X # => 0.333333333
)
~(caseof(1)
| m(int) >> X._in_([1, 2, 3]) # => True
)
~(caseof(lambda x, y: x + y)
| m(callable) >> X(1, 2) # => 3
)
| Operation | Syntax |
|---|---|
| Addition | X + 1 |
| Call | X(a, b, c) |
| Concatenation | X + [1, 2, 3] |
| Containment Test | X._in_( [1, 2, 3] ) |
| Contains | X._contains_(1) |
| Division | X / 2 or X // 2 |
| Bitwise And | X & 2 |
| Bitwise Exclusive Or | X ^ 2 |
| Bitwise Inversion | ~X |
| Bitwise Or | X | 2 |
| Exponentiation | X ** 2 |
| Identity | X._is_(2) |
| Indexing | X[k] |
| Left Shift | X << 2 |
| Modulo | X % 2 |
| Multiplication | X * 2 |
| Matrix Multiplication | X @ matrix |
| Negation (Arithmetic) | -X |
| Negation (Logical) | X._not() |
| Positive | +X |
| Right Shift | X >> 2 |
| Subtraction | X - 2 |
| Ordering | X < 2 or X <= 2 or X > 2 or X >= 2 |
| Equality | X == 2 |
| Difference | X != 2 |
match pattern with XObject
from xpattern import X
from xpattern import caseof
from xpattern import m
~(caseof((1, 2, 3))
| m(X[2] == 3) >> X[2] + 4 # => 7
)
# same as
~(caseof((1, 2, 3))
| m(lambda x: x[2] == 3) >> (lambda x: x[2] + 4) # => 7
)
xfunction
XObject only can represent as function like X(1, 2), but can not be as args in function func(X, X + 2)
Now you can try to use xfunction realizing it!
from xpattern import X
from xpattern import _
from xpattern import caseof
from xpattern import m
from xpattern import xfunction
@xfunction
def add(a, b):
return a + b
# in actions
~(caseof(1)
| m(int) >> add(X, X) # => 2
)
# recursion xfunction
~(caseof(2)
| m(int) >> add(add(X + 1, 4), b=add(X * 9, 7)) # => 32
)
@xfunction
def greater_than_4(x):
return x > 4
# in patterns
~(caseof(1)
| m(greater_than_4(X + 5)) >> "greater than 4"
| _ >> "equal or lesser than 4"
) # => "greater than 4"
~(caseof(1)
| m(greater_than_4(X)) >> "greater than 4"
| _ >> "equal or lesser than 4"
) # => "equal or lesser than 4"
Metadata
Release files for xpattern 0.5.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| xpattern-0.5.0.tar.gz | 10.5 kB | Without provenance | Details for xpattern-0.5.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| xpattern-0.5.0-py3-none-any.whl | Python 3 | none | any | Details for xpattern-0.5.0-py3-none-any.whl |
Total release size: 18.4 kB
Release files / xpattern-0.5.0.tar.gz
| Download URL | xpattern-0.5.0.tar.gz |
|---|---|
| Size | 10.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
6d059c913b0b33674a4928846e871cc40d2c5713f1977fd09811d4de558e5127
|
|
BLAKE2b-256 checksum How to use checksums |
02a3e40c381388234a043615396c849ef85d5b5dbe408b63017129ecf0608e2a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/1.0.3 CPython/3.7.5 Linux/4.15.0-101-generic
|
Release files / xpattern-0.5.0-py3-none-any.whl
| Download URL | xpattern-0.5.0-py3-none-any.whl |
|---|---|
| Size | 7.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
ca7eb9958d7d1b8e3fbe31adc574352f326c833816e1d32715038eb95d792eeb
|
|
BLAKE2b-256 checksum How to use checksums |
7eafd7ccce15fb1c4b19674ac43d0616f4034ddee6a22248c7be6f820bf7f0be
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/1.0.3 CPython/3.7.5 Linux/4.15.0-101-generic
|
Security for xpattern 0.5.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.