[Python-ideas] Pattern matching

Andrew Barnert abarnert at yahoo.com
Wed Apr 8 08:39:36 CEST 2015


On Apr 7, 2015, at 21:56, Chris Angelico <rosuav at gmail.com> wrote:
> 
>> On Wed, Apr 8, 2015 at 12:45 PM, Andrew Barnert <abarnert at yahoo.com> wrote:
>>> On Apr 7, 2015, at 19:04, Chris Angelico <rosuav at gmail.com> wrote:
>>> 
>>> On Wed, Apr 8, 2015 at 7:10 AM, Andrew Barnert
>>> <abarnert at yahoo.com.dmarc.invalid> wrote:
>>>> The smaller problem is that in Python, only functions (and classes and modules) have scope; the idea of a name bound "locally" is tricky. There's a bit of hackery around except clauses...
>>> 
>>> FWIW it's not hackery around scope at all - it's simply that the name
>>> gets unbound:
>> 
>> Sorry, you're right, "hackery" is misleading here; I should have just said "(yes, I know about comprehensions and except clauses, but they're not relevant here)" or something similar. I don't consider the 3.x rules for except "hacky" or bad in any way, and didn't mean to imply otherwise.
> 
> Gotcha.
> 
>> Anyway, an ML/Haskell case expression binds the matched variables inside the case branch; the most obvious interpretation of this proposal (or mine) would bind them in the entire function.
>> Of course it's possible to solve that (if you think it needs solving) either the way comprehensions do (compile the case statement, or each branch, as a function definition and call) or the way except does (unbind names that appear in the "as" clause after the statement), or probably other ways, but if you don't do anything, they work like assignments. (Which is actually a perfectly good parallel to ML, where they work like let expressions, it's just that let expressions don't work like assignments.)
> 
> I'd treat these case branches like 'with' statements. The name binding
> from "as" lasts past the end of the block, it's no different from any
> other assignment. The only reason exceptions unbind is to avoid the
> refloop of an exception having a reference to locals, and the local
> name referencing the exception. Everything else can be just like
> assignment.

Exactly my thought. Binding in Python case statements is different from Haskell case expressions in exactly the same way that assignment statements are different from let expressions, which is pretty much what you should expect.

> So basically, what we have here is a cross between a 'with' statement
> and an 'if'.

I understand why people keep reaching for "with" here, but I really don't like it.

Part of the attraction is the "as" clause, which looks like the "as" clause in an ML case expression. But that's missing the point of patterns: what you mostly want to do is decompose the pattern, binding variables to (some of) the components; you don't want to bind a variable to the whole thing. Except that _occasionally_ you _also_ want to bind the whole thing (or bind a subexpression and also some of its own subexpressions), which is what "as" can add.

Szymon's insight seems to be that pattern matching can be done, not directly in the way Haskell and ML do it, but instead by having types that know how to transform themselves into simpler structures that Python already knows how to decompose (tuples for tuple unpacking when possible--where the "as" clause is useful--and dicts for updating locals for the less-trivial cases where it's not). That's clever, and it makes good use of an "as" clause, but (especially with the locals-updating dict) it seems so far from what a with statement is intended to do that it seems like an abuse to try to fit his solution into that syntax.

Also, "with" just sounds wrong when you read it out loud. Although I'm not sure how much that matters; the same is arguably true with using with to simulate the related but different "if let" statement (as seen in Swift, as Grant sort of proposed in the last email I responded to), but I think I like it there...

> I started writing up a demo that mainly used 'with', and
> then realized that I had no idea how to have the __enter__ method
> stipulate that the body should be skipped... oh, hello PEP 377, that's
> where the problem is.

There are some hacks for getting around that in CPython 2.6-7 or 3.3+, which you can use for experimenting with it. Or you can always use MacroPy to transform the ASTs before it even gets that far.

> This proposal would need some new syntax, but
> conceptually, it'd be something like an __enter__ method returning
> "hey, this body should be skipped", based on whatever criteria it
> likes (isinstance, regex matching, etc).
> 
> ChrisA
> _______________________________________________
> Python-ideas mailing list
> Python-ideas at python.org
> https://mail.python.org/mailman/listinfo/python-ideas
> Code of Conduct: http://python.org/psf/codeofconduct/


More information about the Python-ideas mailing list