[Python-ideas] Pattern Matching Syntax

Chris Angelico rosuav at gmail.com
Thu May 3 14:01:55 EDT 2018

On Fri, May 4, 2018 at 3:18 AM, Ed Kellett <e+python-ideas at kellett.im> wrote:
> I believe the intention in the example you quoted is syntax something like:
>     <match-case> ::= <pattern>
>                    | <pattern> "if" <expression>
> where the expression is a guard expression evaluated in the context of
> the matched pattern.
> IOW, it could be written like this, too:
> number = match x:
>     1 if True => "one"
>     y if isinstance(y, str) => f'The string is {y}'
>     _ if True => "anything"
> I do see a lot of room for bikeshedding around the specific spelling.
> I'm going to try to resist the temptation ;)

Okay, let me try to tease apart your example.

1) A literal matches anything that compares equal to that value.
2) A name matches anything at all, and binds it to that name.
2a) An underscore matches anything at all. It's just a name, and
follows a common convention.
3) "if cond" modifies the prior match; if the condition evaluates as
falsey, the match does not match.
4) As evidenced below, a comma-separated list of comparisons matches a
tuple with as many elements, and each element must match.

Ultimately, this has to be a series of conditions, so this is
effectively a syntax for an elif tree as an expression.

For another example, here's a way to use inequalities to pick a
numeric formatting:

display = match number:
    x if x < 1e3: f"{number}"
    x if x < 1e6: f"{number/1e3} thousand"
    x if x < 1e9: f"** {number/1e6} million **"
    x if x < 1e12: f"an incredible {number/1e9} billion"
    _: "way WAY too many"

I guarantee you that people are going to ask for this to be spelled
simply "< 1e3" instead of having the "x if x" part. :)

> How about this?
> def hyperop(n, a, b):
>     return match (n, a, b):
>         (0, _, b) => b + 1
>         (1, a, 0) => a
>         (2, _, 0) => 0
>         (_, _, 0) => 1
>         (n, a, b) => hyperop(n-1, a, hyperop(n, a, b-1))
> versus:
> def hyperop(n, a, b):
>     if n == 0:
>         return b + 1
>     if n == 1 and b == 0:
>         return a
>     if n == 2 and b == 0:
>         return 0
>     if b == 0:
>         return 1
>     return hyperop(n-1, a, hyperop(n, a, b-1))

I have no idea what this is actually doing, and it looks like a port
of Haskell code. I'd want to rewrite it as a 'while' loop with maybe
one level of recursion in it, instead of two. (Zero would be better,
but I think that's not possible. Maybe?) Is this something that you do
a lot of? Is the tuple (n, a, b) meaningful as a whole, or are the
three values independently of interest?

Not sure how this is useful without a lot more context.


More information about the Python-ideas mailing list