[Python-ideas] Re: Pattern matching in python function headers

2021-08-16 Thread Stephen J. Turnbull
Abdulla Al Kathiri writes:

 > You have a point, but the mathematical approach of Haskell of
 > different function cases is quite readable and straight forward.

You seem to have quite missed that point, though.  The point is that
although borrowing tech from Haskell for Python is a *great* idea
(almost as yuge as "namespaces" ;-), Python is not Haskell, and will
do those things its own way.

In this case we already have a perfectly good syntax for this, it's
just that it occurs in the explicit match statement rather than
implicitly when a function is defined multiple times.

The fact that the Haskell style is often less verbose is likely to
carry zero weight.  The fact that it means two ways of doing the same
thing (one being more general and flexible), is a potential detriment,
although not always an idea killer.

Also, arguing that "other languages do this and it's fine for them"
doesn't help here for syntax -- it frequently does carry weight for
the feature itself (Haskell was mentioned more than once in advocating
some kind of match statement or expression).  You need to argue either
that "this is a common (enough) thing to do and it's so verbose that
this much more concise way of expressing it is much more readable" or
that "this is something that Python can't currently do without [some
horrible hack], and it can't really be expressed in a function, but
this syntax looks very natural in a Python program and does the job".

Nobody will hate on you for disagreeing with all that, but you'll be
more able to get things done if you present syntax proposals in those
ways.

Steve
___
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/DWNEDGALXEWPELPLYYVZXWGCHCKOCFEY/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Pattern matching in python function headers

2021-08-15 Thread Abdulla Al Kathiri
You have a point, but the mathematical approach of Haskell of different 
function cases is quite readable and straight forward. I only coded a little in 
Haskell and I know how to read it. I am not sure if you would consider Rust a 
functional language but they have pattern matching for function parameters but 
only you’re allowed to use one function signature unlike Haskell.

Sent from my iPhone

> On 10 Aug 2021, at 10:53 AM, Steven D'Aprano  wrote:
> 
> On Sun, Aug 08, 2021 at 11:30:20AM +0400, Abdulla Al Kathiri wrote:
> 
>> For me, it looks normal because I am used to seeing pattern matching 
>> for function parameters in functional programming languages.
> 
> Can you give us a few samples from other languages? The only one I know 
> is Haskell:
> 
>fib 0 = 0
>fib 1 = 1
>fib n = fib (n-1) + fib (n-2)
> 
> 
> I don't *hate* that in Haskell, because Haskell is meant to be read 
> almost as mathematical definitions. But Python functions are 
> declarative, and Python code consists of statements which are executed 
> in a defined order. I don't think that's a good match for Haskell-style 
> syntax.
> 
> What's wrong with the straight-forward application of a match statement 
> inside the function body? As you suggest:
> 
>> def fib(*args):
>>match args:
>>case 0, : return 0 
>>case 1, : return 1 
>>case int(n), : 
>>return fib(n-1) + fib(n-2) 
> 
> It costs one extra line (the match statement), but makes it explicit 
> what we're matching. And you save having to repeat the `def fib` for 
> every case.
> 
> Most importantly, it means that we only need one kind of pattern 
> matching syntax, instead of two.
> 
> -- 
> Steve
> ___
> 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/WCOU56EW37ZAC76GNICXR5NOWNNR6GRN/
> Code of Conduct: http://python.org/psf/codeofconduct/
___
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/AZIFHKRXO5LT2FVY4JE7KOFMEOJFNSWU/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Pattern matching in python function headers

2021-08-10 Thread Steven D'Aprano
On Sun, Aug 08, 2021 at 11:30:20AM +0400, Abdulla Al Kathiri wrote:

> For me, it looks normal because I am used to seeing pattern matching 
> for function parameters in functional programming languages.

Can you give us a few samples from other languages? The only one I know 
is Haskell:

fib 0 = 0
fib 1 = 1
fib n = fib (n-1) + fib (n-2)


I don't *hate* that in Haskell, because Haskell is meant to be read 
almost as mathematical definitions. But Python functions are 
declarative, and Python code consists of statements which are executed 
in a defined order. I don't think that's a good match for Haskell-style 
syntax.

What's wrong with the straight-forward application of a match statement 
inside the function body? As you suggest:

> def fib(*args):
>   match args:
>   case 0, : return 0 
>   case 1, : return 1 
>   case int(n), : 
>   return fib(n-1) + fib(n-2) 

It costs one extra line (the match statement), but makes it explicit 
what we're matching. And you save having to repeat the `def fib` for 
every case.

Most importantly, it means that we only need one kind of pattern 
matching syntax, instead of two.

-- 
Steve
___
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/WCOU56EW37ZAC76GNICXR5NOWNNR6GRN/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Pattern matching in python function headers

2021-08-08 Thread Abdulla Al Kathiri
If you are going to add a new case function somewhere in the middle of a REPL 
session because order matters, maybe break it with anything like write a number 
or something.. and then repeat the case functions with the order you wish. Now 
the new case functions will overwrite whatever you wrote before.. We can make a 
rule that the case functions should be below each other. I’ve always seen the 
different functions done above each other in Haskell. 

> On 8 Aug 2021, at 5:10 PM, 2qdxy4rzwzuui...@potatochowder.com wrote:
> 
> Because the order of cases is significant, these would be difficult to
> work with in the REPL.  If, for example, I start with your three
> definitions, and then decide to write a special case¹ for 2, how do I
> convince Python that
> 
>case def fib(2):
>  return 1
> 
> belongs before the general case?
> 
> ¹ Yeah, I know, special cases aren't special enough.  In a non-toy case
> (pun intended), there could be any number of reasons to add a new case
> in the middle, or to redfine/fix a case that already exists rather than
> add a new case to the end.

___
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/REES6S3RED7FYQRE7A4J753V7VZBI7VA/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Pattern matching in python function headers

2021-08-08 Thread 2QdxY4RzWzUUiLuE
On 2021-08-08 at 11:30:20 +0400,
Abdulla Al Kathiri  wrote:

> ... if we write “case” before “def” similar to “async” before “def” in
> async function it should be clear we are doing pattern matching. The
> function will be named case function.
> 
> case def fib(0):
>   return 0
> 
> case def fib(1):
>   return 1
> 
> case def fib(int(n)):
>   return fib(n-1) + fib(n-2) 
> 
> If you none of the parameters you pass match your case functions, an
> exception will be raised ...

Because the order of cases is significant, these would be difficult to
work with in the REPL.  If, for example, I start with your three
definitions, and then decide to write a special case¹ for 2, how do I
convince Python that

case def fib(2):
  return 1

belongs before the general case?

¹ Yeah, I know, special cases aren't special enough.  In a non-toy case
(pun intended), there could be any number of reasons to add a new case
in the middle, or to redfine/fix a case that already exists rather than
add a new case to the end.
___
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/4OWHKTPCNJML7Y5GRKI3DP2KBUFKDZKI/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Pattern matching in python function headers

2021-08-08 Thread Stephen J. Turnbull
Abdulla Al Kathiri writes:

 > case def fib(0):
 >  return 0

This syntax (1) is a new, slightly shorter version of something we can
already do as you point out yourself, and (2) plausibly is something
of a bug magnet if someone does

case def fib(1):
case def fib(2):
def fib(n):

Plausible != probable, but given Python's general conservatism vs.
syntax, I suspect "this bug is improbable" is on you to argue.

Notes:  These comments are not original to me.   I do agree that this
is a plausible syntax, and don't agree with Steven d'A's suggestion
that it might be offputting to new Pythonistas -- I think it could go
either way if implemented.  I just don't think it's particularly
Pythonic or beneficial to Python, so -1.

 > If you none of the parameters you pass match your case functions,
 > an exception will be raised. Maybe it would be easier to make those
 > functions faster since we already know the types in advance.

This claim needs to be supported, and it kinda seems unlikely since we
already have

def fib(n : int) -> int:

(although the optimizer doesn't use such information yet AFAIK).

 > def fib(n):
 >  case 0, : return 0 
 >  case 1, : return 1 
 >  case int(n), :
 >  return fib(n-1) + fib(n-2) 
 > 
 > As opposed to … 
 > 
 > def fib(*args):
 >  match args:
 >  case 0, : return 0 
 >  case 1, : return 1 
 >  case int(n), : 
 >  return fib(n-1) + fib(n-2) 

Saving one line and one level of indentation doesn't seem worth new
syntax.  This kind of claim is easy to address (again, given Python's
conservatism I think it's on the proponents, not the opponents) by
going through the stdlib or some other large codebase (Numpy or Pandas
or requests might be good candidates) and showing that in fact such
dispatching styles would likely bleed off the right edge in many cases
where the project has a tight column limit (such as Python's 79 column
convention, which is much tighter than many Python programmers like).

By the way, what's with the rather strange syntax?  In Python 3.10rc1,

def fib(n):
match n:
case 0: return 0
case 1: return 1
case n if isinstance(n, int) and n > 1:
return fib(n-1) + fib(n-2)
case _: raise RuntimeError

is how I'd write it, although I'm not sure that reusing 'n' that way
is good style (and RuntimeError is the wrong exception but I'm too
lazy to look up the right spelling for args-out-of-range in Python).

Interestingly, I can't find a definition for n that gets fib(1.0) to
error, except by prepending a "case float()".  Not sure if that is
intended, anybody know?

Steve
___
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/3M3IUZFMZBPISDAMOKSW4M7R367R6ZSR/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Pattern matching in python function headers

2021-08-08 Thread Abdulla Al Kathiri
For me, it looks normal because I am used to seeing pattern matching for 
function parameters in functional programming languages. However, if we write 
“case” before “def” similar to “async” before “def” in async function it should 
be clear we are doing pattern matching. The function will be named case 
function. 

case def fib(0):
return 0

case def fib(1):
return 1

case def fib(int(n)):
return fib(n-1) + fib(n-2) 

If you none of the parameters you pass match your case functions, an exception 
will be raised. Maybe it would be easier to make those functions faster since 
we already know the types in advance. 

Another solution would be something like this …. 

def fib(n):
case 0, : return 0 
case 1, : return 1 
case int(n), :
return fib(n-1) + fib(n-2) 

As opposed to … 

def fib(*args):
match args:
case 0, : return 0 
case 1, : return 1 
case int(n), : 
return fib(n-1) + fib(n-2) 
 
 
> On 6 Aug 2021, at 4:46 PM, 2qdxy4rzwzuui...@potatochowder.com wrote:
> 
> On 2021-08-06 at 21:57:47 +1000,
> Steven D'Aprano  wrote:
> 
>> On Thu, Aug 05, 2021 at 09:39:44AM +0100, Sam Frances wrote:
> 
>>> def fib(0):
>>>return 0
>>> 
>>> def fib(1):
>>>return 1
>>> 
>>> def fib(n):
>>>return fib(n-1) + fib(n-2)
>> 
>> I think that there is something rather disturbing about writing a
>> function definition with a constant literal as parameter. It looks
>> wrong and I'm sure it's going to confuse beginners.
> 
> You are not a beginner (nor am I); what's disturbing to you may or may
> not look wrong or confuse someone else.  When I was a beginner,
> x = x + 1 was disturbing, wrong, and confusing to me.
> 
> The proposed definition of the Fibonacci sequence mirrors the ones in
> Wikipedia¹ and OEIS,² and will certainly be at least familiar to those
> with a background in mathematics or coming to Python from functional
> languages.
> 
> That said, I agree that it's not a good fit for Python, for reasons
> expressed elsewhere in this thread.
> 
> FWIW, Lisp Flavored Erlang³ (a syntactically imperative language built
> atop the Erlang VM and run-time) doesn't repeat the "def," only the
> argument lists:
> 
>lfe> (defun ackermann
>   ((0 n) (+ n 1))
>   ((m 0) (ackermann (- m 1) 1))
>   ((m n) (ackermann (- m 1)
> (ackermann m (- n 1)
> 
> Something like that might work in Python, but at that point, it's no
> different from a function that matches on its *args argument.
> 
> ¹ https://en.wikipedia.org/wiki/Fibonacci_number
> ² https://oeis.org/A45
> ³ https://lfe.io/
> ___
> 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/TCBZOFYGD7ZKCK3ITPXOEDZFDZDMDBVX/
> Code of Conduct: http://python.org/psf/codeofconduct/

___
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/EZKM57QB2AP47AQO5GN6ADTFNPJ5SI2L/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Pattern matching in python function headers

2021-08-06 Thread 2QdxY4RzWzUUiLuE
On 2021-08-06 at 21:57:47 +1000,
Steven D'Aprano  wrote:

> On Thu, Aug 05, 2021 at 09:39:44AM +0100, Sam Frances wrote:

> > def fib(0):
> > return 0
> > 
> > def fib(1):
> > return 1
> > 
> > def fib(n):
> > return fib(n-1) + fib(n-2)
> 
> I think that there is something rather disturbing about writing a
> function definition with a constant literal as parameter. It looks
> wrong and I'm sure it's going to confuse beginners.

You are not a beginner (nor am I); what's disturbing to you may or may
not look wrong or confuse someone else.  When I was a beginner,
x = x + 1 was disturbing, wrong, and confusing to me.

The proposed definition of the Fibonacci sequence mirrors the ones in
Wikipedia¹ and OEIS,² and will certainly be at least familiar to those
with a background in mathematics or coming to Python from functional
languages.

That said, I agree that it's not a good fit for Python, for reasons
expressed elsewhere in this thread.

FWIW, Lisp Flavored Erlang³ (a syntactically imperative language built
atop the Erlang VM and run-time) doesn't repeat the "def," only the
argument lists:

lfe> (defun ackermann
   ((0 n) (+ n 1))
   ((m 0) (ackermann (- m 1) 1))
   ((m n) (ackermann (- m 1)
 (ackermann m (- n 1)

Something like that might work in Python, but at that point, it's no
different from a function that matches on its *args argument.

¹ https://en.wikipedia.org/wiki/Fibonacci_number
² https://oeis.org/A45
³ https://lfe.io/
___
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/TCBZOFYGD7ZKCK3ITPXOEDZFDZDMDBVX/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Pattern matching in python function headers

2021-08-06 Thread Chris Angelico
On Fri, Aug 6, 2021 at 9:59 PM Steven D'Aprano  wrote:
> > def fib(0):
> > return 0
> >
> > def fib(1):
> > return 1
> >
> > def fib(n):
> > return fib(n-1) + fib(n-2)
>
> I think that there is something rather disturbing about writing a
> function definition with a constant literal as parameter. It looks wrong
> and I'm sure it's going to confuse beginners.

Agreed, but that's because Python behaves differently.

But we already have a way to have a function-ish thing that then
changes behaviour: a property's .setter/.deleter modifiers. Borrowing
an idea from that:

@multidispatch
def fib(n): return fib(n-1) + fib(n-2)
@fib.specialize(n=0)
def fib(n): return 0
@fib.specialize(n=1)
def fib(n): return 1

I'm not really a fan, but (a) it does avoid the "literal as parameter"
problem, and (b) it fits Python's syntax.

> If we did allow the use of literals as parameters, what would happen if
> we ran some other code in between the cases of the function?
>
> def fib(0):
> return 0
>
> print("suprise!")
>
> def fib(1):
> return 1
>
>
> We would, apparently, have two distinct modes:
>
> - sometimes re-defining a function replaces the previous binding;
>
> - but other times, it extends the function with a new case.
>
> What are the rules for each?

Agreed. Use of a dedicated specialization operation would avoid this
problem. Obviously you wouldn't normally want to do it, but if you
did, the behaviour in between those steps would be well-defined:
specializations not yet applied would not be used, and the function
would execute using the generic form.

(Also, I don't think you'd ever want to do it, but you could have a
specialization in a different scope from the generic one. The
decorator would attach the specialization to the generic.)

> > def allow_entry({"name": "Bob"}):
> > return "Bob is not allowed in ever!"
>
> I don't know how to interpret that syntax. Does that mean `allow_entry`
> takes a single argument, which much be a dictionary with a single key,
> 'name'?
>
> result = allow_entry({'name': 'Bob'})
> assert result = "Bob is not allowed in ever!"
>
> If that's not what you mean, then how would I write a function that
> *actually does* literally match the dict `{'name': 'Bob'}`?

Presumably the behaviour would be the same as the match statement.

https://www.python.org/dev/peps/pep-0622/#mapping-patterns

And that's where any proposal based on current syntax is going to fall
down. It's easy enough to build something like singledispatch, but
much much harder to make something that can handle the full
flexibility of match statements. So you're left with two options: a
simpler version that lets you build up the patterns from multiple
functions, or the full-power version that has a single master function
that can do the dispatching.

To be quite honest, I would usually just write it as a single function
with a match statement in it. But there are definitely times when I've
wanted to be able to build up pattern matching in a more declarative
way (think of what can be done with Flask's request routing, for
instance), and maybe there'd be enough to justify something like that.

ChrisA
___
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/LXXM7HDG6E5WJRWZHNQGWXFEP35MVGLM/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Pattern matching in python function headers

2021-08-06 Thread Steven D'Aprano
On Fri, Aug 06, 2021 at 04:17:55PM +0800, Mxzixl wrote:

> Consider ML-style? :D
> 
> ```
> 
> def fib(n):
>     | n == 0 = 0
>     | n == 1 = 1
>     | otherwise  = fib(n-1) + fib(n-2)


I like the look of this when I read Haskell code. We can bike-shed the 
syntax, but I think that's more promising than multiple function 
definitions.



-- 
Steve
___
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/7XMCXNBCQL72GMUCDUC5JB72O27ERZXJ/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Pattern matching in python function headers

2021-08-06 Thread Steven D'Aprano
On Fri, Aug 06, 2021 at 09:30:57AM +0100, Sam Frances wrote:

> All good points. To me there is an elegance in being able to split the
> different paths of the function into their own syntactically separate
> function definitions.

Do you use `functools.singledispatch`? Thatt gets you part-way there.


> One place where this excels is in handling happy paths vs error paths.
> It increases clarity substantially, in my experience, to be able to code
> the happy path without separately from the error path.

I don't know... it seems to me that the error path is generally going to 
be a single statement, `raise SomeException(message)`. Does that really 
need to be its own function?

It might help if you show some real code rather than trivial examples 
like recursive fibonacci and made-up toy functions.


-- 
Steve
___
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/YS4HVH5GFHVXXLRIIZZPH5NXRHJZPKSR/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Pattern matching in python function headers

2021-08-06 Thread Steven D'Aprano
On Thu, Aug 05, 2021 at 09:39:44AM +0100, Sam Frances wrote:

> Following on from PEP 634, it would be good to be able to have Erlang /
> Elixir-style pattern matching in function headers.

This was recently discussed here:

https://mail.python.org/archives/list/python-ideas@python.org/message/ROYZNX4U5VMWZMJJ7AZY6KUGGJ2HYKGX/


> def fib(0):
> return 0
> 
> def fib(1):
> return 1
> 
> def fib(n):
> return fib(n-1) + fib(n-2)

I think that there is something rather disturbing about writing a 
function definition with a constant literal as parameter. It looks wrong 
and I'm sure it's going to confuse beginners.

Let us remember that Python's execution model is not the same as Erlang 
or Elixir. In Python, when you write:

def fib(a): ...

def fib(b): ...


that is not a single compile-time declaration, it is a pair of run-time 
statements. In pseudo-code:

# create a function, bind it to the name "fib"
fib = make_function( ... )

# create a new function, bind it to the same name,
# garbage collecting the first function
fib = make_function( ... )


So we would need a radical and major change in the execution model of 
Python to turn your example into a single function using pattern- 
matching multiple-dispatch.

If we did allow the use of literals as parameters, what would happen if 
we ran some other code in between the cases of the function?

def fib(0):
return 0

print("suprise!")

def fib(1):
return 1


We would, apparently, have two distinct modes:

- sometimes re-defining a function replaces the previous binding;

- but other times, it extends the function with a new case.

What are the rules for each?


The nice thing about Python is that we (mostly) have a very predictable, 
consistent execution model. Syntax is not generally context-dependent, 
so you can usually interpret the meaning of code by considering it in 
isolation, rather than by tracking the context. (With a few simple 
modifiers, such as `global`.)

For example:

def func(arg): ...

creates a function object named "func", and binds it to the name "func" 
in the local namespace. That applies whether the def statement is inside 
a class, nested inside another function, in the top-level module, inside 
a for-loop or if-statement, etc.

Because of that consistent behaviour, if we want to use generic 
functions, we use the singledispatch decorator. This has the advantage 
of making it explicit and obvious that we're doing generic functions.



> def allow_entry({"name": "Bob"}):
> return "Bob is not allowed in ever!"

I don't know how to interpret that syntax. Does that mean `allow_entry` 
takes a single argument, which much be a dictionary with a single key, 
'name'?

result = allow_entry({'name': 'Bob'})
assert result = "Bob is not allowed in ever!"

If that's not what you mean, then how would I write a function that 
*actually does* literally match the dict `{'name': 'Bob'}`?



-- 
Steve
___
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/OJL2V2Z27L7E4ZZ6Z4BHQTDB3HOAIV3O/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Pattern matching in python function headers

2021-08-06 Thread Mxzixl

Consider ML-style? :D

```

def fib(n):
    | n == 0 = 0
    | n == 1 = 1
    | otherwise  = fib(n-1) + fib(n-2)

def allow_entry(d):
    | d == {"name": "Bob"} = "Bob is not allowed in ever!"
    | d == {"name": "Charles", "day": "Tuesday"} = \
 "It's a Tuesday, so Charles is allowed in."
    | d == {"name": "Charles", "day": _}) = \
 "Charles is only allowed in on a Tuesday."
    | d == {"name": name} = f"Come in {name}, make yourself at home!"

```


On 05/08/2021 16:39, Sam Frances wrote:

Following on from PEP 634, it would be good to be able to have Erlang /
Elixir-style pattern matching in function headers.

(I don't know what the technical term is for this language feature, but
hopefully the examples will clarify.)

Here's the obligatory fibonacci example:

```
def fib(0):
 return 0

def fib(1):
 return 1

def fib(n):
 return fib(n-1) + fib(n-2)
```

Or, another example:

```
def allow_entry({"name": "Bob"}):
 return "Bob is not allowed in ever!"

def allow_entry({"name": "Charles", "day": "Tuesday"}):
 return "It's a Tuesday, so Charles is allowed in."

def allow_entry({"name": "Charles", "day": _}):
 return "Charles is only allowed in on a Tuesday."

def allow_entry({"name": name}):
 return f"Come in {name}, make yourself at home!"
```

Thanks for considering my idea.

Kind regards

Sam Frances
___
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/OPLBLWJPCN66QRUQNHBQSQOBNBFZRRBF/
Code of Conduct: http://python.org/psf/codeofconduct/


___
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/DTLRX2OSMHCNDPZRLHL6XENWJPCWVT46/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Pattern matching in python function headers

2021-08-06 Thread Sam Frances
All good points. To me there is an elegance in being able to split the
different paths of the function into their own syntactically separate
function definitions.

One place where this excels is in handling happy paths vs error paths.
It increases clarity substantially, in my experience, to be able to code
the happy path without separately from the error path.

```
def foo("error")
# do some error handling

def foo(n):
# code the happy path
```

Whether this is worth the extra syntax, as you put it, I'm not sure.

I don't think I have the knowledge to write a PEP that has a reasonable
chance of adoption, so at this point I'm just "offering the idea".

On 05/08/2021 10:24, Paul Moore wrote:
> I assume that such a feature would simply behave exactly the same as a
> match statement:
> 
> def fib(arg):
> match arg:
> case 0:
> return 0
> case 1:
> return 1
> case n:
> return fib(n-1) + fib(n-2)
> # I know this is only a trivial example,
> # but you should probably also handle
> # n < 0. Does your proposal cover using
> # guards, or would they need a conditional
> # in the final case?
> 
> def allow_entry(arg):
> match arg:
> case {"name": "Bob"}:
> return "Bob is not allowed in ever!"
> case {"name": "Charles", "day": "Tuesday"}:
> return "It's a Tuesday, so Charles is allowed in."
> case {"name": "Charles", "day": _}:
> return "Charles is only allowed in on a Tuesday."
> case {"name": name}:
> return f"Come in {name}, make yourself at home!"
> # I only skimmed the PEP, and I don't have a copy of Python 3.10 to check,
> # but I believe that if arg doesn't match any of the given
> clauses, the match
> # silently does nothing. I don't know if that was your expected
> behaviour for
> # the definition form, but you should probably be explicit about
> what you intend
> # in any case.
> 
> Note that I created these by taking your examples and applying a
> purely mechanical translation - I didn't think about it at all, so
> this transformation could easily be applied mechanically. What's the
> benefit that would justify having this additional syntax?
> 
> In addition, you'd need to consider the implications of possibilities
> you didn't cover in your examples. I don't know Elixir, so I can't say
> whether that language has similar scenarios that we could follow, but
> these are all valid in Python, so we need to consider them.
> 
> Python's function definitions are executed at runtime, so you need to
> decide what behaviour you want from a function definition that's had
> *some* of its parts executed, but not others. So how would the
> following behave?
> 
> def example(1):
> return "One"
> 
> print(example(2))
> 
> def example(2):
> return "Two"
> 
> print(example(2))
> 
> Worse, what if the example(2) definition were in a separate module?
> 
> What about decorators?
> 
> def example(1):
> return "One"
> 
> @some_decorator
> def example(2):
> return "Two"
> 
> That's just a very brief list of "things to think about". In
> functional languages, I like this style of function definition, but it
> would need some fairly careful design to be able to translate it to a
> language like Python. And honestly, I'm not sure I see the advantage
> (in Python).
> 
> I'm not against the suggestion as such, but I think it will need a
> fair amount of work to flesh it out from a series of basic examples to
> a full-fledged proposal (which even then might end up getting
> rejected). Is that something you're considering doing yourself, or are
> you just offering the idea in case someone else is interested in
> picking it up?
> 
> Paul
> 
> On Thu, 5 Aug 2021 at 09:52, Sam Frances  wrote:
>>
>> Following on from PEP 634, it would be good to be able to have Erlang /
>> Elixir-style pattern matching in function headers.
>>
>> (I don't know what the technical term is for this language feature, but
>> hopefully the examples will clarify.)
>>
>> Here's the obligatory fibonacci example:
>>
>> ```
>> def fib(0):
>> return 0
>>
>> def fib(1):
>> return 1
>>
>> def fib(n):
>> return fib(n-1) + fib(n-2)
>> ```
>>
>> Or, another example:
>>
>> ```
>> def allow_entry({"name": "Bob"}):
>> return "Bob is not allowed in ever!"
>>
>> def allow_entry({"name": "Charles", "day": "Tuesday"}):
>> return "It's a Tuesday, so Charles is allowed in."
>>
>> def allow_entry({"name": "Charles", "day": _}):
>> return "Charles is only allowed in on a Tuesday."
>>
>> def allow_entry({"name": name}):
>> return f"Come in {name}, make yourself at home!"
>> ```
>>
>> Thanks for considering my idea.
>>
>> Kind regards
>>
>> Sam Frances
>> ___
>> Python-ideas mailing list -- python-ideas@python.org
>> To unsubscribe send an email to python-ideas-le...@python.org
>> 

[Python-ideas] Re: Pattern matching in python function headers

2021-08-05 Thread Paul Moore
I assume that such a feature would simply behave exactly the same as a
match statement:

def fib(arg):
match arg:
case 0:
return 0
case 1:
return 1
case n:
return fib(n-1) + fib(n-2)
# I know this is only a trivial example,
# but you should probably also handle
# n < 0. Does your proposal cover using
# guards, or would they need a conditional
# in the final case?

def allow_entry(arg):
match arg:
case {"name": "Bob"}:
return "Bob is not allowed in ever!"
case {"name": "Charles", "day": "Tuesday"}:
return "It's a Tuesday, so Charles is allowed in."
case {"name": "Charles", "day": _}:
return "Charles is only allowed in on a Tuesday."
case {"name": name}:
return f"Come in {name}, make yourself at home!"
# I only skimmed the PEP, and I don't have a copy of Python 3.10 to check,
# but I believe that if arg doesn't match any of the given
clauses, the match
# silently does nothing. I don't know if that was your expected
behaviour for
# the definition form, but you should probably be explicit about
what you intend
# in any case.

Note that I created these by taking your examples and applying a
purely mechanical translation - I didn't think about it at all, so
this transformation could easily be applied mechanically. What's the
benefit that would justify having this additional syntax?

In addition, you'd need to consider the implications of possibilities
you didn't cover in your examples. I don't know Elixir, so I can't say
whether that language has similar scenarios that we could follow, but
these are all valid in Python, so we need to consider them.

Python's function definitions are executed at runtime, so you need to
decide what behaviour you want from a function definition that's had
*some* of its parts executed, but not others. So how would the
following behave?

def example(1):
return "One"

print(example(2))

def example(2):
return "Two"

print(example(2))

Worse, what if the example(2) definition were in a separate module?

What about decorators?

def example(1):
return "One"

@some_decorator
def example(2):
return "Two"

That's just a very brief list of "things to think about". In
functional languages, I like this style of function definition, but it
would need some fairly careful design to be able to translate it to a
language like Python. And honestly, I'm not sure I see the advantage
(in Python).

I'm not against the suggestion as such, but I think it will need a
fair amount of work to flesh it out from a series of basic examples to
a full-fledged proposal (which even then might end up getting
rejected). Is that something you're considering doing yourself, or are
you just offering the idea in case someone else is interested in
picking it up?

Paul

On Thu, 5 Aug 2021 at 09:52, Sam Frances  wrote:
>
> Following on from PEP 634, it would be good to be able to have Erlang /
> Elixir-style pattern matching in function headers.
>
> (I don't know what the technical term is for this language feature, but
> hopefully the examples will clarify.)
>
> Here's the obligatory fibonacci example:
>
> ```
> def fib(0):
> return 0
>
> def fib(1):
> return 1
>
> def fib(n):
> return fib(n-1) + fib(n-2)
> ```
>
> Or, another example:
>
> ```
> def allow_entry({"name": "Bob"}):
> return "Bob is not allowed in ever!"
>
> def allow_entry({"name": "Charles", "day": "Tuesday"}):
> return "It's a Tuesday, so Charles is allowed in."
>
> def allow_entry({"name": "Charles", "day": _}):
> return "Charles is only allowed in on a Tuesday."
>
> def allow_entry({"name": name}):
> return f"Come in {name}, make yourself at home!"
> ```
>
> Thanks for considering my idea.
>
> Kind regards
>
> Sam Frances
> ___
> 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/OPLBLWJPCN66QRUQNHBQSQOBNBFZRRBF/
> Code of Conduct: http://python.org/psf/codeofconduct/
___
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/FYPEKJSXND4NU4XXBTF5I7JOV7MKOTHZ/
Code of Conduct: http://python.org/psf/codeofconduct/