pymatched⇒
What is pymatched?
pymatched is a library which provides functional pattern matching.
Installation
pip install pymatched
Syntax
result = match(<'func'>) >> Mapping[Hashable, Any]
Match order
- exact match
- oneof match
- placeholder match (if target is immutable iterable)
- type match with guard (Contravariant match)
- type match (Invariant match)
- type match (Contravariant match)
- handling default if exists
Usage
Note: How to match mutable value?
as you know, mutable things cannot be key of dict so we can not match easly.
this is the example of list.
Case A: use type guards
x = match([1, 2, 3]) >> {
list : "list",
oneof([1], [1, 2], [1, 2, 3]) : "[1] | [1, 2] | [1, 2, 3]",
(list, lambda x: x == [1, 2, 3]): "(list, f(list) -> bool)",
}
Case B: use nested match
x = match([1, 2, 3]) >> {
list: match(...) >> {
(list, lambda v: v == [1, _, 3]): "pattern is (1, * ,3)",
... : "default"
}
}
Value match
from pymatched import match
match(1) >> {
1: "It's 1",
5: "It's 5",
}
Handling default case
use elipsis ...
or typing.Any
if nothing catched but default handler not defined, RuntimeError will be raised.
from typing import Any
from pymatched import match
match(None) >> {
...: "default",
}
Type match
from pymatched import match
match(42) >> {
int: "int caught",
...: lambda v: f"{type(v)} caught"
}
Type match with guard
If tuple's first element is type and second element is lambda, this case will be considered as type match with guard.
from pymatched import match
match(42) >> {
(int, lambda: v: v == 42): "42 caught",
int : "int except 42",
}
type match with guard can use typing.Any
.
from typing import Any
from pymatched import match
match(42) >> {
(Any, lambda: v: v in (42, "42")): "42 caught",
int : "int except 42",
}
Exception match in type match
pymatched.do
wraps executing function. when wrapped function raises error, do
catch it and return it as normal return.
from pymatched import match, do
def fx(v):
raise Exception("Ooops!")
match(do(fx, None)) >> {
Exception: "exception caught",
... : lambda v: f"{v} caught",
}
Oneof match
from pymatched import oneof, match
fx = lambda x: x
match(fx(5)) >> {
oneof(1, 2, 3): "one of 1, 2, 3",
oneof(4, 5, 6): "one of 4, 5, 6",
}
Placeholder match
from pymatched import oneof, match
match((1, 2, 3, 4)) >> {
(1, _, 3, _): "pattern (1, *, 3, *)",
(_, 2, _, 4): "pattern (*, 2, *, 4)",
}
Nested match
If match with pymatchied._
(PlaceholderTyoe) or ...
(Ellipsis), this match will be considered as nested match.
from pymatched import match, _
match(5) >> {
int: match(_) >> {
5: "It's 5",
...: "default"
},
}
Mixed match
cases could be mixed, but resolved by designated match order.
from pymatched import oneof, match
v = (1, 2, 3)
x = match(v) >> {
tuple : "Tuple caught",
(tuple, lambda v: v[-1] == 3) : "last item of tuple is 3",
(1, _, 3) : "pattern is (1, *, 3)".
oneof((1,), (1, 2), (1, 2, 3)): "one of (1,) | (1, 2) | (1, 2, 3)",
(1, 2, 3) : "(1, 2, 3)"
}