PEP 312 – Simple Implicit Lambda
- Author:
- Roman Suzi <rnd at onego.ru>, Alex Martelli <aleaxit at gmail.com>
- Status:
- Deferred
- Type:
- Standards Track
- Created:
- 11-Feb-2003
- Python-Version:
- 2.4
- Post-History:
Table of Contents
Abstract
This PEP proposes to make argumentless lambda keyword optional in some cases where it is not grammatically ambiguous.
Deferral
The BDFL hates the unary colon syntax. This PEP needs to go back to the drawing board and find a more Pythonic syntax (perhaps an alternative unary operator). See python-dev discussion on 17 June 2005 [1].
Also, it is probably a good idea to eliminate the alternative
propositions which have no chance at all. The examples section
is good and highlights the readability improvements. It would
carry more weight with additional examples and with real-world
referents (instead of the abstracted dummy calls to :A
and :B
).
Motivation
Lambdas are useful for defining anonymous functions, e.g. for use as callbacks or (pseudo)-lazy evaluation schemes. Often, lambdas are not used when they would be appropriate, just because the keyword “lambda” makes code look complex. Omitting lambda in some special cases is possible, with small and backwards compatible changes to the grammar, and provides a cheap cure against such “lambdaphobia”.
Rationale
Sometimes people do not use lambdas because they fear to introduce a term with a theory behind it. This proposal makes introducing argumentless lambdas easier, by omitting the “lambda” keyword. itself. Implementation can be done simply changing grammar so it lets the “lambda” keyword be implied in a few well-known cases. In particular, adding surrounding brackets lets you specify nullary lambda anywhere.
Syntax
An argumentless “lambda” keyword can be omitted in the following cases:
- immediately after “=” in named parameter assignment or default value assignment;
- immediately after “(” in any expression;
- immediately after a “,” in a function argument list;
- immediately after a “:” in a dictionary literal; (not implemented)
- in an assignment statement; (not implemented)
Examples of Use
- Inline
if
:def ifelse(cond, true_part, false_part): if cond: return true_part() else: return false_part() # old syntax: print ifelse(a < b, lambda:A, lambda:B) # new syntax: print ifelse(a < b, :A, :B) # parts A and B may require extensive processing, as in: print ifelse(a < b, :ext_proc1(A), :ext_proc2(B))
- Locking:
def with(alock, acallable): alock.acquire() try: acallable() finally: alock.release() with(mylock, :x(y(), 23, z(), 'foo'))
Implementation
Implementation requires some tweaking of the Grammar/Grammar
file
in the Python sources, and some adjustment of
Modules/parsermodule.c
to make syntactic and pragmatic changes.
(Some grammar/parser guru is needed to make a full implementation.)
Here are the changes needed to Grammar
to allow implicit lambda:
varargslist: (fpdef ['=' imptest] ',')* ('*' NAME [',' '**'
NAME] | '**' NAME) | fpdef ['=' imptest] (',' fpdef ['='
imptest])* [',']
imptest: test | implambdef
atom: '(' [imptestlist] ')' | '[' [listmaker] ']' |
'{' [dictmaker] '}' | '`' testlist1 '`' | NAME | NUMBER | STRING+
implambdef: ':' test
imptestlist: imptest (',' imptest)* [',']
argument: [test '='] imptest
Three new non-terminals are needed: imptest
for the place where
implicit lambda may occur, implambdef
for the implicit lambda
definition itself, imptestlist
for a place where imptest
’s may
occur.
This implementation is not complete. First, because some files in Parser module need to be updated. Second, some additional places aren’t implemented, see Syntax section above.
Discussion
This feature is not a high-visibility one (the only novel part is the absence of lambda). The feature is intended to make null-ary lambdas more appealing syntactically, to provide lazy evaluation of expressions in some simple cases. This proposal is not targeted at more advanced cases (demanding arguments for the lambda).
There is an alternative proposition for implicit lambda: implicit
lambda with unused arguments. In this case the function defined by
such lambda can accept any parameters, i.e. be equivalent to:
lambda *args: expr
. This form would be more powerful. Grep in the
standard library revealed that such lambdas are indeed in use.
One more extension can provide a way to have a list of parameters
passed to a function defined by implicit lambda. However, such
parameters need some special name to be accessed and are unlikely
to be included in the language. Possible local names for such
parameters are: _
, __args__
, __
. For example:
reduce(:_[0] + _[1], [1,2,3], 0)
reduce(:__[0] + __[1], [1,2,3], 0)
reduce(:__args__[0] + __args__[1], [1,2,3], 0)
These forms do not look very nice, and in the PEP author’s opinion do not justify the removal of the lambda keyword in such cases.
Credits
The idea of dropping lambda was first coined by Paul Rubin at 08 Feb 2003 16:39:30 -0800 in comp.lang.python while discussing the thread “For review: PEP 308 - If-then-else expression” [2].
References
Copyright
This document has been placed in the public domain.
Source: https://github.com/python/peps/blob/main/peps/pep-0312.rst
Last modified: 2023-09-09 17:39:29 GMT