2003-02-14 00:49:58 -05:00
|
|
|
|
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:
|
|
|
|
|
|
2003-02-14 09:51:27 -05:00
|
|
|
|
|
2003-02-14 00:49:58 -05:00
|
|
|
|
Abstract
|
|
|
|
|
|
|
|
|
|
This PEP proposes to make argumentless lambda keyword optional in
|
|
|
|
|
some cases where it is not grammatically ambiguous.
|
|
|
|
|
|
2003-02-14 09:51:27 -05:00
|
|
|
|
|
2003-02-14 00:49:58 -05:00
|
|
|
|
Motivation
|
|
|
|
|
|
|
|
|
|
Lambdas are useful for defining anonymous functions, e.g. for use
|
|
|
|
|
as callbacks or (pseudo)-lazy evaluation schemes. Often, lambdas
|
2003-02-14 09:51:27 -05:00
|
|
|
|
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".
|
|
|
|
|
|
2003-02-14 00:49:58 -05:00
|
|
|
|
|
|
|
|
|
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.
|
2003-02-14 09:51:27 -05:00
|
|
|
|
In particular, adding surrounding brackets lets you specify
|
|
|
|
|
nullary lambda anywhere.
|
|
|
|
|
|
2003-02-14 00:49:58 -05:00
|
|
|
|
|
|
|
|
|
Syntax
|
|
|
|
|
|
2003-02-14 09:51:27 -05:00
|
|
|
|
An argumentless "lambda" keyword can be omitted in the following
|
|
|
|
|
cases:
|
2003-02-14 00:49:58 -05:00
|
|
|
|
|
2003-02-14 09:51:27 -05:00
|
|
|
|
* immediately after "=" in named parameter assignment or default
|
|
|
|
|
value assignment;
|
2003-02-14 00:49:58 -05:00
|
|
|
|
|
|
|
|
|
* immediately after "(" in any expression;
|
|
|
|
|
|
|
|
|
|
* immediately after a "," in a function argument list;
|
|
|
|
|
|
2003-02-14 09:51:27 -05:00
|
|
|
|
* immediately after a ":" in a dictionary literal; (not
|
|
|
|
|
implemented)
|
2003-02-14 00:49:58 -05:00
|
|
|
|
|
|
|
|
|
* in an assignment statement; (not implemented)
|
|
|
|
|
|
2003-02-14 09:51:27 -05:00
|
|
|
|
|
2003-02-14 00:49:58 -05:00
|
|
|
|
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'))
|
|
|
|
|
|
2003-02-14 09:51:27 -05:00
|
|
|
|
|
2003-02-14 00:49:58 -05:00
|
|
|
|
Implementation
|
|
|
|
|
|
|
|
|
|
Implementation requires some tweaking of the Grammar/Grammar file
|
2003-02-14 09:51:27 -05:00
|
|
|
|
in the Python sources, and some adjustment of
|
|
|
|
|
Modules/parsermodule.c to make syntactic and pragmatic changes.
|
2003-02-14 00:49:58 -05:00
|
|
|
|
|
2003-02-14 09:51:27 -05:00
|
|
|
|
(Some grammar/parser guru is needed to make a full
|
|
|
|
|
implementation.)
|
2003-02-14 00:49:58 -05:00
|
|
|
|
|
|
|
|
|
Here are the changes needed to Grammar to allow implicit lambda:
|
|
|
|
|
|
|
|
|
|
varargslist: (fpdef ['=' imptest] ',')* ('*' NAME [',' '**'
|
|
|
|
|
NAME] | '**' NAME) | fpdef ['=' imptest] (',' fpdef ['='
|
|
|
|
|
imptest])* [',']
|
|
|
|
|
|
|
|
|
|
imptest: test | implambdef
|
|
|
|
|
|
2003-02-14 09:51:27 -05:00
|
|
|
|
atom: '(' [imptestlist] ')' | '[' [listmaker] ']' |
|
2003-02-14 00:49:58 -05:00
|
|
|
|
'{' [dictmaker] '}' | '`' testlist1 '`' | NAME | NUMBER | STRING+
|
|
|
|
|
|
|
|
|
|
implambdef: ':' test
|
2003-02-14 09:51:27 -05:00
|
|
|
|
|
2003-02-14 00:49:58 -05:00
|
|
|
|
imptestlist: imptest (',' imptest)* [',']
|
|
|
|
|
|
|
|
|
|
argument: [test '='] imptest
|
|
|
|
|
|
2003-02-14 09:51:27 -05:00
|
|
|
|
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.
|
2003-02-14 00:49:58 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
|
2003-02-14 09:51:27 -05:00
|
|
|
|
|
2003-02-14 00:49:58 -05:00
|
|
|
|
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".
|
|
|
|
|
|
2003-02-14 09:51:27 -05:00
|
|
|
|
|
2003-02-14 00:49:58 -05:00
|
|
|
|
Copyright
|
|
|
|
|
|
|
|
|
|
This document has been placed in the public domain.
|
|
|
|
|
|
2003-02-14 09:51:27 -05:00
|
|
|
|
|
2003-02-14 00:49:58 -05:00
|
|
|
|
|
|
|
|
|
Local Variables:
|
|
|
|
|
mode: indented-text
|
|
|
|
|
indent-tabs-mode: nil
|
|
|
|
|
sentence-end-double-space: t
|
|
|
|
|
fill-column: 70
|
|
|
|
|
End:
|