Just a minor editorial thing on the PEP text:

The section https://www.python.org/dev/peps/pep-0622/#case-clauses presents
a simplified syntax. That one mentions "group_pattern", but the document
never mentions (in prose) what a group pattern is. It confused me until I
found the definition in the full grammar, which seems to refer to those
sequence patterns using () rather than []. Probably it makes more sense for
a quick read to remove the "| group_pattern" from the simplified grammar,
it looks more like an intermediate construct.

On Tue, 23 Jun 2020 at 17:04, Guido van Rossum <gu...@python.org> wrote:

> I'm happy to present a new PEP for the python-dev community to review.
> This is joint work with Brandt Bucher, Tobias Kohn, Ivan Levkivskyi and
> Talin.
>
> Many people have thought about extending Python with a form of pattern
> matching similar to that found in Scala, Rust, F#, Haskell and other
> languages with a functional flavor. The topic has come up regularly on
> python-ideas (most recently yesterday :-).
>
> I'll mostly let the PEP speak for itself:
> - Published: https://www.python.org/dev/peps/pep-0622/ (*)
> - Source: https://github.com/python/peps/blob/master/pep-0622.rst
>
> (*) The published version will hopefully be available soon.
>
> I want to clarify that the design space for such a match statement is
> enormous. For many key decisions the authors have clashed, in some cases we
> have gone back and forth several times, and a few uncomfortable compromises
> were struck. It is quite possible that some major design decisions will
> have to be revisited before this PEP can be accepted. Nevertheless, we're
> happy with the current proposal, and we have provided ample discussion in
> the PEP under the headings of Rejected Ideas and Deferred Ideas. Please
> read those before proposing changes!
>
> I'd like to end with the contents of the README of the repo where we've
> worked on the draft, which is shorter and gives a gentler introduction than
> the PEP itself:
>
>
> # Pattern Matching
>
> This repo contains a draft PEP proposing a `match` statement.
>
> Origins
> -------
>
> The work has several origins:
>
> - Many statically compiled languages (especially functional ones) have
>   a `match` expression, for example
>   [Scala](
> http://www.scala-lang.org/files/archive/spec/2.11/08-pattern-matching.html
> ),
>   [Rust](https://doc.rust-lang.org/reference/expressions/match-expr.html),
>   [F#](
> https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/pattern-matching
> );
> - Several extensive discussions on python-ideas, culminating in a
>   summarizing
>   [blog post](
> https://tobiaskohn.ch/index.php/2018/09/18/pattern-matching-syntax-in-python/
> )
>   by Tobias Kohn;
> - An independently developed [draft
>   PEP](
> https://github.com/ilevkivskyi/peps/blob/pattern-matching/pep-9999.rst)
>   by Ivan Levkivskyi.
>
> Implementation
> --------------
>
> A full reference implementation written by Brandt Bucher is available
> as a [fork]((https://github.com/brandtbucher/cpython/tree/patma)) of
> the CPython repo.  This is readily converted to a [pull
> request](https://github.com/brandtbucher/cpython/pull/2)).
>
> Examples
> --------
>
> Some [example code](
> https://github.com/gvanrossum/patma/tree/master/examples/) is available
> from this repo.
>
> Tutorial
> --------
>
> A `match` statement takes an expression and compares it to successive
> patterns given as one or more `case` blocks.  This is superficially
> similar to a `switch` statement in C, Java or JavaScript (an many
> other languages), but much more powerful.
>
> The simplest form compares a target value against one or more literals:
>
> ```py
> def http_error(status):
>     match status:
>         case 400:
>             return "Bad request"
>         case 401:
>             return "Unauthorized"
>         case 403:
>             return "Forbidden"
>         case 404:
>             return "Not found"
>         case 418:
>             return "I'm a teapot"
>         case _:
>             return "Something else"
> ```
>
> Note the last block: the "variable name" `_` acts as a *wildcard* and
> never fails to match.
>
> You can combine several literals in a single pattern using `|` ("or"):
>
> ```py
>         case 401|403|404:
>             return "Not allowed"
> ```
>
> Patterns can look like unpacking assignments, and can be used to bind
> variables:
>
> ```py
> # The target is an (x, y) tuple
> match point:
>     case (0, 0):
>         print("Origin")
>     case (0, y):
>         print(f"Y={y}")
>     case (x, 0):
>         print(f"X={x}")
>     case (x, y):
>         print(f"X={x}, Y={y}")
>     case _:
>         raise ValueError("Not a point")
> ```
>
> Study that one carefully!  The first pattern has two literals, and can
> be thought of as an extension of the literal pattern shown above.  But
> the next two patterns combine a literal and a variable, and the
> variable is *extracted* from the target value (`point`).  The fourth
> pattern is a double extraction, which makes it conceptually similar to
> the unpacking assignment `(x, y) = point`.
>
> If you are using classes to structure your data (e.g. data classes)
> you can use the class name followed by an argument list resembling a
> constructor, but with the ability to extract variables:
>
> ```py
> from dataclasses import dataclass
>
> @dataclass
> class Point:
>     x: int
>     y: int
>
> def whereis(point):
>     match point:
>         case Point(0, 0):
>             print("Origin")
>         case Point(0, y):
>             print(f"Y={y}")
>         case Point(x, 0):
>             print(f"X={x}")
>         case Point():
>             print("Somewhere else")
>         case _:
>             print("Not a point")
> ```
>
> We can use keyword parameters too.  The following patterns are all
> equivalent (and all bind the `y` attribute to the `var` variable):
>
> ```py
> Point(1, var)
> Point(1, y=var)
> Point(x=1, y=var)
> Point(y=var, x=1)
> ```
>
> Patterns can be arbitrarily nested.  For example, if we have a short
> list of points, we could match it like this:
>
> ```py
> match points:
>     case []:
>         print("No points")
>     case [Point(0, 0)]:
>         print("The origin")
>     case [Point(x, y)]:
>         print(f"Single point {x}, {y}")
>     case [Point(0, y1), Point(0, y2)]:
>         print(f"Two on the Y axis at {y1}, {y2}")
>     case _:
>         print("Something else")
> ```
>
> We can add an `if` clause to a pattern, known as a "guard".  If the
> guard is false, `match` goes on to try the next `case` block.  Note
> that variable extraction happens before the guard is evaluated:
>
> ```py
> match point:
>     case Point(x, y) if x == y:
>         print(f"Y=X at {x}")
>     case Point(x, y):
>         print(f"Not on the diagonal")
> ```
>
> Several other key features:
>
> - Like unpacking assignments, tuple and list patterns have exactly the
>   same meaning and actually match arbitrary sequences.  An important
>   exception is that they don't match iterators or strings.
>   (Technically, the target must be an instance of
>   `collections.abc.Sequence`.)
>
> - Sequence patterns support wildcards: `[x, y, *rest]` and `(x, y,
>   *rest)` work similar to wildcards in unpacking assignments.  The
>   name after `*` may also be `_`, so `(x, y, *_)` matches a sequence
>   of at least two items without binding the remaining items.
>
> - Mapping patterns: `{"bandwidth": b, "latency": l}` extracts the
>   `"bandwidth"` and `"latency"` values from a dict.  Unlike sequence
>   patterns, extra keys are ignored.  A wildcard `**rest` is also
>   supported.  (But `**_` would be redundant, so it not allowed.)
>
> - Subpatterns may be extracted using the walrus (`:=`) operator:
>
>   ```py
>   case (Point(x1, y1), p2 := Point(x2, y2)): ...
>   ```
>
> - Patterns may use named constants.  These must be dotted names; a
>   single name can be made into a constant value by prefixing it with a
>   dot to prevent it from being interpreted as a variable extraction:
>
>   ```py
>   RED, GREEN, BLUE = 0, 1, 2
>
>   match color:
>       case .RED:
>           print("I see red!")
>       case .GREEN:
>           print("Grass is green")
>       case .BLUE:
>           print("I'm feeling the blues :(")
>   ```
>
> - Classes can customize how they are matched by defining a
>   `__match__()` method.
>   Read the [PEP](
> https://github.com/python/peps/blob/master/pep-0622.rst#runtime-specification)
> for details.
>
>
>
> --
> --Guido van Rossum (python.org/~guido)
> *Pronouns: he/him **(why is my pronoun here?)*
> <http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-change-the-world/>
> _______________________________________________
> Python-Dev mailing list -- python-dev@python.org
> To unsubscribe send an email to python-dev-le...@python.org
> https://mail.python.org/mailman3/lists/python-dev.python.org/
> Message archived at
> https://mail.python.org/archives/list/python-dev@python.org/message/RFW56R7LTSC3QSNIZPNZ26FZ3ZEUCZ3C/
> Code of Conduct: http://python.org/psf/codeofconduct/
>
_______________________________________________
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/SRPECWGZJTTXDOYLBVRYZIHCQMUDJ6B5/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to