[Python-Dev] Let's just *keep* lambda

Bengt Richter bokr at oz.net
Fri Feb 10 01:16:30 CET 2006


On Thu, 9 Feb 2006 10:33:10 -0800, Guido van Rossum <guido at python.org> wrote:

>Enough already.
>
>As has clearly been proven, lambda is already perfect.
>
[...]
>
>To those people still complaining that lambda is crippled because it
>doesn't do statements: First, remember that adding statement
>capability wouldn't really add any power to the language; lambda is
>purely syntactic sugar for an anonymous function definition (see above
>myth debunking section). Second, years of attempts to overcome this
>haven't come up with a usable syntax (and yes, curly braces have been
Yes, but if you're an optimist, those years mean we're closer to the magic moment ;-)

>proposed and rejected like everything else). It's a hard problem
>because switching back to indentation-based parsing inside an
>expression is problematic. For example, consider this hypothetical
>example:
>
>a = foo(lambda x, y:
>      print x
>      print y)
>
>Should this be considered legal? Or should it be written as
>
>a = foo(lambda x, y:
>          print x
>          print y
>        )
>
Neither. If I may ;-)
First, please keep the existing expression lambda exactly as is.

Second, allow a new lambda variant to have a suite. But this necessitates:

1. same suite syntax as a function def suite, with explicit returns of values
   except if falling out with a default None. Just like a function def.

2. diffentiating the variant lambda, and providing for suite termination.
   2a. differentiate by using doubled ':'
       a = foo(lambda x, y :: print x+y)

   2b. the lambda:: variant _requires_ enclosing parens, and the top suite ends at the closing ')'
       A calling context may be sufficient parens, but sometimes, like tuple expressions,
       yet another pair of enclosing expression-parens may be needed.

   2c. Single-line suites terminate on closing paren. Hence
       a = foo(lambda x, y :: print x; print y)  # is ok

   2d. For multiline suites, the first line after the one with the '::' defines
       the column of a single indent (COLSI), at the first non-whitepace character.
       Further indents work normally and terminate by dedent, or the closing ')' may be placed
       anywhere convenient to terminate the  whole lambda suite. Any statement dedenting to left
       of the established single indent column (COLSI) before the closing ')' is a syntax error.
       I recognize that this requires keeping track of independent nested indentation contexts,
       but that part of tokenizing was always fun, I imagine. I'd volunteer to suffer appropriately
       if you like this (the lambda variant, I mean, not my suffering ;-)

I think that's it, though I'm always prepared for a d'oh moment ;-)

>??? (Indenting the prints so they start at a later column than the 'l'
>of 'lambda', and adding an explicit dedent before the close
>parenthesis.) Note that if the former were allowed, we'd have
>additional ambiguity if foo() took two parameters, e.g.:
>
>a = foo(lambda x, y:
>      print x
>      print y, 42)
>
>-- is 42 the second argument to foo() or is it printed?
To make 42 a second argument, it would be spelled

    a = foo((lambda x, y::
           print x
           print y), 42)

to have the "print y, 42" statement, you could move the closing paren like

    a = foo((lambda x, y::
           print x
           print y, 42))

but that would have redundant parens with the same meaning as

    a = foo(lambda x, y::
           print x
           print y, 42)

Though perhaps requiring the redundant parens for _all_
(lambda::) expressions would make the grammar easier.
>
>I'd much rather avoid this snake's nest by giving the function a name
>and using existing statement syntax, like this:
This is Python! How can a snake's nest be bad? ;-)

Seriously, with the above indentation rules it seems straightforward to me.
I do think it would be hard to do something reasonable without an explicitly
differentiated lambda variant though.

>
>def callback(x, y):
>    print x
>    print y
>a = foo(callback)
vs
    a = foo(lambda x, y :: print x; print y)
>
>This is unambiguous, easier to parse (for humans as well as for
>computers), and doesn't actually span more text lines. Since this
Well, it does use more lines when :: allows simple statement suites ;-)

>typically happens in a local scope, the name 'callback' disappears as
>soon as as the scope is exited.
>
>BTW I use the same approach regularly for breaking up long
>expressions; for example instead of writing
>
>a = foo(some_call(another_call(some_long_argument,
>                               another_argument),
>                  and_more(1, 2, 3),
>        and_still_more())
>
>I'll write
>
>x = another_call(some_long_argument, another_argument)
>a = foo(some_call(x, and_more(1, 2, 3)), and_still_more())
>
>and suddenly my code is more compact and yet easier to read! (In real
>life, I'd use a more meaningful name than 'x', but since the example
>is nonsense it's hard to come up with a meaningful name here. :-)
>
I can't argue with any of that, except that I think I would like to be
able to do both styles. Sometimes it's nice to define right
in the context of one-shot use, e.g., I could see writing

    ss = sorted(seq, key=(lambda x::
            try: return abs(x)
            except TypeError: return 0))

(unless I desperately wanted to avoid the LOAD_CONST, MAKE_FUNCTION
overhead of using an inline lambda at all. I guess that does favor
a global def done once).

>
>Parting shot: it appears that we're getting more and more
>expressionized versions of statements: first list comprehensions, then
>generator expressions, most recently conditional expressions, in
>Python 3000 print() will become a function... Seen this way, lambda
>was just ahead of its time! Perhaps we could add a try/except/finally
>expression, and allow assignments in expressions, and then we could
>rid of statements altogether, turning Python into an expression
>language. Change the use of parentheses a bit, and... voila, Lisp! :-)
><duck>
Well, if you want to do it, (lambda args::suite) is perhaps a start.
I promise not to use it immoderately ;-)
<ducking further>

Regards,
Bengt Richter



More information about the Python-Dev mailing list