160 lines
5.2 KiB
Plaintext
160 lines
5.2 KiB
Plaintext
|
PEP: 312
|
|||
|
Title: Simple Implicit Lambda
|
|||
|
Version: $Revision$
|
|||
|
Last-Modified: $Date$
|
|||
|
Author: Roman Suzi <rnd at onego.ru>, Alex Martelli <aleax at aleax.it>
|
|||
|
Status: Draft
|
|||
|
Type: Standards Track
|
|||
|
Content-Type: text/plain
|
|||
|
Created: 11-Feb-2003
|
|||
|
Python-Version: 2.4
|
|||
|
Post-History:
|
|||
|
|
|||
|
Abstract
|
|||
|
|
|||
|
This PEP proposes to make argumentless lambda keyword optional in
|
|||
|
some cases where it is not grammatically ambiguous.
|
|||
|
|
|||
|
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
|
|||
|
|
|||
|
1) 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))
|
|||
|
|
|||
|
2) 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".
|
|||
|
|
|||
|
Copyright
|
|||
|
|
|||
|
This document has been placed in the public domain.
|
|||
|
|
|||
|
|
|||
|
Local Variables:
|
|||
|
mode: indented-text
|
|||
|
indent-tabs-mode: nil
|
|||
|
sentence-end-double-space: t
|
|||
|
fill-column: 70
|
|||
|
End:
|
|||
|
|