PEP: 312
Title: Simple Implicit Lambda
Version: $Revision: 2073 $
Last-Modified: $Date: 2005-06-17 15:19:41 -0700 (Fri, 17 Jun 2005) $
Author: Roman Suzi , Alex Martelli
Status: Deferred
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.

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.

    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
    referrents (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

    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.