[Python-ideas] The Return of Implicit Lambda (Re: Allowing breaks in generator expressions by overloading the while keyword)

Andrew Barnert abarnert at yahoo.com
Fri Feb 21 23:49:03 CET 2014


From: Ryan Gonzalez <rymg19 at gmail.com>
Sent: Friday, February 21, 2014 2:09 PM


>On Fri, Feb 21, 2014 at 4:02 PM, Andrew Barnert <abarnert at yahoo.com> wrote:
>
>From: Ryan Gonzalez <rymg19 at gmail.com>
>>Sent: Friday, February 21, 2014 1:36 PM
>>
>>
>>
>>>On Fri, Feb 21, 2014 at 2:34 PM, Andrew Barnert <abarnert at yahoo.com> wrote:
>>>
>>>From: Nick Coghlan <ncoghlan at gmail.com>
>>>>
>>>>Sent: Friday, February 21, 2014 4:18 AM
>>>>
>>>>
>>>>> On 21 February 2014 20:24, Steven D'Aprano <steve at pearwood.info>
>>>>> wrote:
>>>>>>
>>>>>>  but alas both Nick Coglan and (if I recall correctly) Guido have ruled
>>>>>>  that Python won't get this, so until the Revolution comes, it isn't
>>>>>>  going to happen.
>>>>>
>>>>> It's not that it can't happen - it's that someone would need to
>>>>> build
>>>>> a case of a similar calibre to the one Chris Angelico is currently
>>>>> putting together for except expressions in PEP 463 :)
>>>>>
>>>>> However, it's a *much* bigger challenge in this case, as
>>>>> itertools.takewhile exists, whereas there's currently no way to do
>>>>> exception handling as part of a larger expression without major
>>>>> contortions.
>>>>>
>>>>> Re-reading Andrew's post at
>>>>> http://stupidpythonideas.blogspot.com.au/2013/07/syntactic-takewhile.html,
>>>>> I'm actually more intrigued by Haskell's shorthand for lambda
>>>>> functions that consist of a single binary operator.
>>>>>
>>>>> Consider:
>>>>>
>>>>>     isprime = all(n % p for p in takewhile((lambda p: p**2 < n),
>>>>> primes_seen))
>>>>>
>>>>> Is there are a nicer way to write that? The Haskell equivalent is:
>>>>>
>>>>>    (< n) . (** 2)
>>>>> 
>>>>
>>>>> That's not very readable to most Python programmers
>>>>
>>>>That's really not a shorthand for lambda, it's a combination of other features that make lambdas often unnecessary. I think the C++ boost::lambda example is a better fit:
>>>>
>>>>    _1 ** 2 < n
>>>>
>>>>> but what if you
>>>>
>>>>> could write something like:
>>>>>
>>>>>     isprime = all(n % p for p in takewhile((: ? ** 2 < n), primes_seen))
>>>>
>>>>I like this. The ? is a lot better than the _ or _1 I suggested (especially to people who do a lot of SQL programming in Python and already use ? as an inline parameter), and using a colon makes it explicit without adding too much visual noise. The only concern is whether using up one of the handful of as-yet-unused ASCII symbols raises the bar a little too high…
>>>>
>>>>> This is somewhat similar to the implicit lambda proposal in
>>>>
>>>>> http://legacy.python.org/dev/peps/pep-0312/, but with the following
>>>>> two essential differences:
>>>>>
>>>>> 1. The parentheses would be required (as per generator expressions,
>>>>> and as is being discussed for except expressions)
>>>>> 2. By using a "?" token within the implicit lambda, you would create a
>>>>> lambda that takes a single argument. If there is no such token, then
>>>>> it would take no arguments.
>>>>
>>>>Would it be worth extending this to multiple arguments? I think it would be handy, but I can't think of any way to make it look nearly as good as the 0- and 1-arg forms.
>>>>
>>>>Obviously this should still be a one-arg lambda that just uses its parameter repeatedly:
>>>>
>>>>    : ? * x**2 + ? * x + ?
>>>>
>>>>Sticking a number on the ? looks terrible:
>>>>
>>>>    : ?1 * x**2 + ?2 * x + ?3
>>>>
>>>>Looking at the other DB-API 2.0 param styles, this is hideous because of the way it uses colons twice:
>>>>
>>>>
>>>>    : :1 * x**2 + :2 * x + :3
>>>>
>>>>Something like this wouldn't be too bad, except that it already has a much more useful meaning, set literals:
>>>>
>>>>    : {1} * x**2 + {2} * x + {3}
>>>>
>>>>So really, the best I can come up with is the boost::lambda version I already didn't like and you already dismissed without comment:
>>>>
>>>>    : _1 * x**2 + _2 * x + _3
>>>>
>>>>On the other hand, any expression this complex—even with just one parameter—is already starting to look pretty bad as an implicit lambda, and the downsides of an explicit lambda go down the longer it gets. So maybe the best answer is:
>>>>
>>>>    lambda a, b, c: a * x**2 + b * x + c
>>>>
>>>>Anyway, we can always start with just 0- and 1-argument forms and come back to expand the idea later, right?
>>>>
>>>>> However, the examples in that PEP are no longer useful, as they have
>>>>> since been addressed by dedicated constructs (conditional expressions
>>>>> in PEP 308 and context managers in PEP 343).
>>>>>
>>>>> Note that I'm not saying this is a good idea. However, I am saying I
>>>>> think it is an idea that may be worth exploring further to see if it
>>>>> also addresses at least some of the use cases given in PEP's 403 and
>>>>> 3150 (especially in combination with PEP 463) by making custom key and
>>>>> predicate functions easier to define.
>>>>
>>>>I'll start digging up some examples; it is hard to predict how nice this will look until we see it in a wide range of realistic code.
>>>>_______________________________________________
>>>>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/
>>
>>
>>>+1 for the question mark. However, there's the problem of multi-argument lambdas. The ?(number) looks to much like Perl. What about something like ? being an array of arguments?
>>
>>
>>Doesn't that just make it even _more_ like perl, where arguments are always passed as an array?
>>
>>Anyway, presumably you mean that this:
>>
>>    lambda *args: args[0] * x**2 + args[1] * x + args[2]
>>
>>… could be written as:
>>
>>    : ?[0] * x**2 + ?[1] * x + ?[2]
>>
>>
>>I think that's horribly unreadable—partly because of the use of *args in the first place, and partly because ?[0] looks too… perlesque.
>>
>>I think the best answer is the one I suggested above—and which I think Nick implicitly assumed because he's smart enough to get there directly: At least initially, just do 0-argument and 1-argument lambdas. As long as you leave the door open for extended syntaxes in a future proposal, we don't need to figure them out yet.
>>
>The question mark still looks like Perl.
>
>
>What about a reserved word instead?


I can't think of any existing keyword that (a) is unambiguous in that syntax, or (b) doesn't read like someone with Wernicke's aphasia substituting random words. But I suppose a _new_ keyword could work:

    : arg **2 < n

And that seems like it could be extended to multiple arguments pretty nicely by adding a "keyword schema", or just a parse rule that matches "arg" digit * instead of "arg":

    : arg1 * x**2 + arg2 * x + arg3

However, I'm pretty sure "arg" is used in lots of real-life code, especially in this context:

    if __name__ == '__main__':
        import sys
        for arg in sys.argv[1:]:
            print(spam(arg))

Any suggestions for a better keyword?



More information about the Python-ideas mailing list