[Python-ideas] Syntax for passing lambdas to functions

Haoyi Li haoyi.sg at gmail.com
Wed Feb 26 20:52:50 CET 2014


I do not feel that this is worth it for the specific case. Having a more
generic "better syntax for lambdas" will do everything that this does, +
add less heterogeneity to the language, + is useful in other places too.



On Wed, Feb 26, 2014 at 11:44 AM, Andrew Barnert <abarnert at yahoo.com> wrote:

> From: Greg Ewing <greg.ewing at canterbury.ac.nz>
>
> Sent: Tuesday, February 25, 2014 4:17 PM
>
>
> > I was reading a blog post here:
> >
> > http://stupidpythonideas.blogspot.co.nz/2014/02/fixing-lambda.html
> >
> > where the author points out that there are a number
> > of different problems that the various enhanced-lambda
> > proposals are trying to solve, which are best addressed
> > by different solutions.
> >
> > Here's a suggestion for one of them. Suppose we could
> > write things like:
> >
> >    sorted(things, key(x) = x.date)
> >
> >    Button("Do it!", on_click() = fire_the_ducks())
>
>
> Of course that particular case would be better written as:
>
>     Button("Do it!", on_click = fire_the_ducks)
>
>
> But it becomes more useful if you do anything else:
>
>     Button("Do it!", on_click() = fire_the_ducks(42))
>
>
> At first glance, I think this is nice, but there's a nagging feeling that
> it may be a bit magical. Maybe if I think through what the compiler will do
> with it, I can resolve that feeling. (Obviously real users aren't going to
> care how it gets parsed and compiled, but if it's simple and clear enough,
> that implies that it can also be simple and clear to a human reader. Not
> perfectly, but... anyway, let's try it.) I'll do that at the end.
>
>
> > It only addresses the case of passing a function using
>
> > a keyword argument
>
> It also doesn't look quite as nice when the function comes first, but I
> think it's still pretty nice:
>
>     itertools.takewhile(predicate(x)=x<5, iterable=spam)
>
> And functions that take a function and then *args, like map, would be
> tricky, but then it's fine if this doesn't work nicely in every possible
> case for passing a function around.
>
> Also, this _could_ be extended to work in all cases where call expressions
> raise a SyntaxError, although I don't know that it _should_ be. For
> example, people who for whatever reason prefer to write "f = lambda x: ..."
> instead of "def f(x): return ..." today would probably love being able to
> write "f(x) = ...", but I don't really want to encourage those people...
>
> > but I think it would make for very
> > readable code in those cases. And it doesn't use any
> > colons!
>
>
> I don't understand the problem with the colons, but never mind that; I
> agree that it's very readable. And the real benefit to me is that it
> doesn't require any new and potentially weird syntax, like Nick's magic ?
> parameter, for the one-argument case.
>
> On the other hand, could this add any confusion? Today, we have:
>
>     Button("Do it!", on_click=fire_the_ducks) # good
>
>     Button("Do it!", on_click=fire_the_ducks()) # bad, passes call result
> as function
>
>     Button("Do it!", on_click=lambda: fire_the_ducks()) # good
>
>     Button("Do it!", on_click=lambda: fire_the_ducks) # bad, passes
> function returning function
>
>
> We'd be adding:
>
>     Button("Do it!", on_click()=fire_the_ducks()) # good
>
>     Button("Do it!", on_click()=fire_the_ducks) # bad, passes function
> returning function
>
>
> Would that last case add to the novices' confusion?
>
> And now, the parsing:
>
> First, in the grammar (see 6.3.4 Calls), you have to expand the left side
> of keyword_item.
>
> The simplest idea is:
>
>     keyword_item = identifier [ "(" [parameter-list] ")" ] "=" expression
>
> Then, the keyword AST node expands to take all the same args-related
> attributes of the Lambda node:
>
>     keyword(arg="on_click", args=[], vararg=None, kwonlyargs=[],
> kw_defaults=[], kwargs=None, value=Call(...))
>
> Then, at compile time, if args is None, you just compile arg and value as
> today and push them on the stack; if it's not (even an empty list), you
> instead compile args, vararg, ..., value together as a function, just as you
> would a Lambda node except that "body" is called "value",then push the arg
> and that function on the stack.
>
> That doesn't feel right. On the other hand, there's a simpler way to do it:
>
>
>     keyword_item ::= simple_keyword_item | functional_keyword_item
>     simple_keyword_item = identifier "=" expression
>     functional_keyword_item = identifier "(" [parameter_list] ")" "="
> expression
>
> Now, simple_keyword_item parses to the same keyword AST node as today, and
> functional_keyword_item also parses into a normal keyword node, which has a
> normal Lambda node as a value, built from the parameter_list and expression
> the exact same way as in a lambda expression.
>
> That seems pretty clear and simple, but now at the AST level there's no
> way to distinguish between "key(x)=x.date" and "key=lambda x: x.date". Is
> that acceptable?
>
> Last, there's always a hybrid: create a new KeyLambda node that has the
> same attributes as Lambda and compiles the same but can be distinguished
> from it by type, and maybe even a funckeyword that's identical to keyword
> as well. Then, no magic, and no irreversible parse either.
> _______________________________________________
> 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/
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-ideas/attachments/20140226/b76b5fbf/attachment.html>


More information about the Python-ideas mailing list