On Jan 1, 2020, at 07:03, Steven D'Aprano <st...@pearwood.info> wrote:
> 
> On Tue, Dec 31, 2019 at 02:28:26PM -0800, Andrew Barnert via Python-ideas 
> wrote:
> 
>>    if try 0, y, z := vec:
>>        # do yz plane stuff
>>    elif try x, 0, z := vec:
>>        # do xz plane stuff
>>    elif try x, y, 0 := vec:
>>        # do xy plane stuff
>>    elif x, y, z := vec:
>>        # do slow/imprecise/whatever 3D stuff
>>    else:
>>        raise TypeError(f'{vec} is not a 3-vector!')
> 
> Comments below.
> 
> 
>> Alternatively, this could just be a try expression that can be used 
>> anywhere: it’s truthy if evaluating doesn’t raise, falsey if it does. 
>> But I don’t think it’s needed anywhere but if/elif.
> 
> Have you read the exception catching PEP?
> 
> https://www.python.org/dev/peps/pep-0463/

Yes. It’s a red herring here—except for the fact they’re incompatible proposals 
(I believe an if-try statement and an if statement with a try-except condition 
would be impossible to disambiguate without look ahead), so this proposal would 
mean that rejected PEP couldn’t be revived.

(Which I think is a bit of a shame, because I liked PEP 463, but it was 
rejected, and nobody’s come up with any good counters to the arguments against 
it in the succeeding half decade, so…)

> I really like the F# pattern matching syntax, even if it would require 
> two new keywords (match, when) and an arrow symbol (F# uses -> but 
> Python could use a colon). That reads nicely to me (and also supports 
> guard clauses, although that's not needed in your example):
> 
>    # F# syntax
>    match vec with
>    | 0, y, z -> yz_expression
>    | x, 0, z -> xz_expression
>    | x, y, 0 -> xy_expression
>    | x, y, z -> xyz_expression
>    | _ -> fail

F# is similar to most other ML-family languages here. I’ve looked at them, but 
also at Scala, Swift, Haskell, C#, and other languages. But I don’t think we 
want to just copy any one of them.

While I like the bar syntax used by a lot of ML derivatives, I don’t think it 
fits nicely with Python. You have a compound statement that doesn’t end with a 
colon or have an indebted suite, a symbol that acts much like an INDENT token 
but not quite and that can only be disambiguated contextually, …

> In F# matching is an expression. I don't know if that's an advantage or 
> disadvantage.

Well, it’s an advantage in the same way that making _all_ statements into 
expressions is an advantage.

Python benefits from making if, for, def, class, etc. into statements and 
having a rigid statement syntax (which uses indentation and other things to aid 
readability). It does give up a bit of expressiveness for doing so, but it’s 
generally worth it. And then, for a small subset of them, it adds a handful of 
explicitly restricted forms (ternary expression, comprehension, lambda) that 
are useful for special cases where you very commonly have something short and 
simple that is worth doing in the middle of an expression. But when you don’t 
have something short and simple that needs to be in the middle of an expression 
(or you do, but it isn’t close enough to one of the three super-common cases to 
have a concise form), you use the more powerful statement form.

I’m pretty sure the same would be true for pattern matching.

(Also note that F# matches are let expressions in disguise. You can introduce a 
new binding (or rebind an existing one), except by evaluating an expression 
inside a let that chains in front of the current environment. And that 
restricts the way you can design pattern matching in ML-family languages.

> I find the F# explanation for what pattern matching is all about *much* 
> more understandable than the Haskell version -- even the "Gentle 
> Introduction".

Yeah, Haskell’s gentle introduction isn’t all that gentle about almost 
anything. If you want to learn the core features of the whole language (and are 
interested in how to use what features and why, rather than how to 
mathematically model each feature), Learn You a Haskell for Great Good is a lot 
better. But it’s not very good for learning a single feature in isolation. I 
don’t actually know of any Haskell resource that’s good for that.

If you want to compare some other languages, maybe look at Scala and Swift 
before Haskell.

> We don't need anything new to get prototype pattern matching.
> 
> Patterns are first class values in SNOBOL (and maybe in Icon?).

String patterns aren’t really the same thing as deconstructing patterns. String 
patterns are first class values in Python too with the re module or a 
third-party module of your choice. They even have dedicated syntax in Ruby and 
Perl.

> Using 
> that as inspiration, we could create Pattern objects to do the work, and 
> a match function that we call like this:
> 
>    # Fail() is a function that raises an exception;
>    # __ is a special predefined Pattern that always matches.
> 
>    result = match(vec, # object to match
>              Pattern(0, 'y', 'z'), handle_yz,
>              Pattern('x', 0, 'z'), handle_xz,
>              Pattern('x', 'y', 0), handle_xy,
>              Pattern('x', 'y', 'z'), handle_xyz,
>              __, Fail('not a vector')
>              )

Yes, and there are already multiple libraries on PyPI that do effectively this.

And by the same token, we don’t need if statements or if exoressions, because 
you can do that with a function:

    def if_(cond, truefunc, falsefunc):
        return [falsefunc, truefunc][bool(cond)]()

Now, instead of this:

    if spam:
        print('spam!')
    else:
        print(f'spam is falsey: {spam}')

… you can write this:

    if_(spam, lambda: print('spam'), lambda: print(f'spam is falsey: {spam}'))

And, because expressions don’t care about whitespace, you can indent that 
however you like.

And you can do the same for for statements—but you don’t have to, because 
that’s already a builtin, map.

Syntax for these things is just sugar, but it’s useful sugar. Being able to 
refer to variables as variables rather than passing around their names as 
strings, and to refer to other targets as well, and to be able to write bodies 
as statement suites inline instead of having to wrap them up in functions, and 
to access and even rebind locals, and so on—these are all useful for if, and 
for for, and for pattern matching, for the exact same reasons.

And I believe all the cons of doing things the Lisp way for pattern matching 
are exactly way nobody uses those existing libraries.

_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/LV6XZHVAZVC5SPRKXEK64MI4RNEL5AOO/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to