Matching module

The Match module

This module implements a technique for pattern matching.

IDEA: Statement-oriented matcher within the same scope: with ValueMatcher(‘sum’, 1, 2, 3) as m:

with m.case(‘sum’, Any, Any, Any) as _, one, two, three:
print(one + two + three)
with m.case(‘avg’, …) as _, *values:
print(sum(*values))
with.m.miss() as *missed:
print(‘MISS!’)

High-level functions

kingston.match.matches(values: Sequence[T_co], patterns: Sequence[T_co], matchfn: Callable = <function match>) → Sequence[T_co][source]

Tries to match values from patterns.

Parameters:
  • values – A sequence of values to match.
  • patterns – A sequence of patterns that may match values.
Returns:

The pattern that was matched or Miss.

Return type:

Union[Sequence, Type[Miss]]

High-level classes

class kingston.match.Matcher[source]

Common base for all matcher classes.

Since Matcher is also Generic, you use it to subtype concrete instances of matchers you implement.

class kingston.match.TypeMatcher[source]

Concrete implementation of a type matcher instance.

If you want to type a type matcher, use standard technique when using Generic types:

>>> from kingston.match import Matcher, TypeMatcher
>>> my_int_matcher:Matcher[int, int] = TypeMatcher({
...    int: lambda x: x+1,
...    str: lambda x: 'str'})
>>> my_int_matcher(10)
11
>>> my_int_matcher(20)
21
>>> my_int_matcher('foo')  # ok at runtime but fails mypy
'str'
>>>

It will try to give a reasonably human representation when inspected:

>>> my_int_matcher
<TypeMatcher: (int)->λ, (str)->λ >
>>>

You can also subclass type matchers and use a decorator to declare cases as methods:

>>> from kingston.match import Matcher, TypeMatcher, case
>>> from numbers import Number
>>> class NumberDescriber(TypeMatcher):
...    @case
...    def describe_one_int(self, one:int) -> str:
...        return "One integer"
...
...    @case
...    def describe_two_ints(self, one:int, two:int) -> str:
...        return "Two integers"
...
...    @case
...    def describe_one_float(self, one:float) -> str:
...        return "One float"
>>> my_num_matcher:Matcher[Number, str] = NumberDescriber()
>>> my_num_matcher(1)
'One integer'
>>> my_num_matcher(1, 2)
'Two integers'
>>> my_num_matcher(1.0)
'One float'
>>>
class kingston.match.ValueMatcher[source]

Concrete implementation of a value matching instance.

If you want to type a type matcher, use standard technique when using Generic types:

>>> from kingston.match import ValueMatcher, Miss
>>> my_val_matcher:Matcher[int, str] = ValueMatcher({
...    1: lambda x: 'one!',
...    2: lambda x: 'two!',
...    Miss: lambda x: 'many!'})
>>> my_val_matcher(1)
'one!'
>>> my_val_matcher(2)
'two!'
>>> my_val_matcher(3)
'many!'
>>> my_val_matcher('x')  # ok at runtime but fails mypy (& missleading..)
'many!'
>>>

It will try to give a reasonably human representation when inspected:

>>> my_val_matcher
<ValueMatcher: (1)->λ, (2)->λ, (<class 'kingston.match.Miss_'>)->λ >
>>>

You can also declare cases as methods in a custom ValueMatcher subclass.

Use the function value_case() to declare value cases. Note: imported as a shorthand:

>>> from kingston.match import Matcher, ValueMatcher
>>> from kingston.match import value_case as case
>>> class SimplestEval(ValueMatcher):
...     @case(Any, '+', Any)
...     def _add(self, a, op, b) -> int:
...         return a + b
...
...     @case(Any, '-', Any)
...     def _sub(self, a, op, b) -> int:
...         return a - b
>>> simpl_eval = SimplestEval()
>>> simpl_eval(1, '+', 2)
3
>>> simpl_eval(10, '-', 5)
5

Exceptions and symbols

exception kingston.match.Mismatch[source]

Exception to signal matching error in Matcher objects.

exception kingston.match.Conflict[source]

Exception raised if a pattern to be matched already have been applied to a Matcher instance.

kingston.match.Miss
class kingston.match.NoNextValue[source]

Symbol signifying that no more values are available to pattern check for.

class kingston.match.NoNextAnchor[source]

Symbol signifying that no more anchor values exist in a pattern.

Low-level functions

kingston.match.match(cand: Any, pattern: Any) → bool[source]

”Primitive” function that checks an individual value against another. The match() function is only responsible for checking two values, matching markers Any and Ellipsis are handled elsewhere.

kingston.match.move(matched: Sequence[T_co], pending: Sequence[T_co], matchfn: Callable = <function match>) → Tuple[Sequence[T_co], Sequence[T_co]][source]