[Python-Dev] Adventures with ASTs - Inline Lambda

Talin talin at acm.org
Thu Feb 16 08:05:09 CET 2006


First off, let me apologize for bringing up a topic that I am sure that 
everyone is sick of: Lambda.

I broached this subject to a couple of members of this list privately, 
and I got wise feedback on my suggestions which basically amounted to 
"don't waste your time."

However, after having thought about this for several weeks, I came to 
the conclusion that I felt so strongly about this issue that the path of 
wisdom simply would not do, and I would have to choose the path of 
folly. Which I did.

In other words, I went ahead and implemented it. Actually, it wasn't too 
bad, it only took about an hour of reading the ast.c code and the 
Grammar file (neither of which I had ever looked at before) to get the 
general sense of what's going on.

So the general notion is similar to the various proposals on the Wiki - 
an inline keyword which serves the function of lambda. I chose the 
keyword "given" because it reminds me of math textbooks, e.g. "given x, 
solve for y". And I like the idea of syntactical structures that make 
sense when you read them aloud.

Here's an interactive console session showing it in action.

The first example shows a simple closure that returns the square of a 
number.

    >>> a = (x*x given x)
    >>> a(9)
    81

You can also put parens around the argument list if you like:

    >>> a = (x*x given (x))
    >>> a(9)
    81

Same thing with two arguments, and with the optional parens:

    >>> a = (x*y given x,y)
    >>> a(9, 10)
    90
    >>> a = (x*y given (x,y))
    >>> a(9, 10)
    90

Yup, keyword arguments work too:

    >>> a = (x*y given (x=3,y=4))
    >>> a(9, 10)
    90
    >>> a(9)
    36
    >>> a()
    12

Use an empty paren-list to indicate that you want to define a closure 
with no arguments:

    >>> a = (True given ())
    >>> a()
    True

Note that there are some cases where you have to use the parens around 
the arguments to avoid a syntactical ambiguity:

    >>> map( str(x) given x, (1, 2, 3, 4) )
      File "<stdin>", line 1
        map( str(x) given x, (1, 2, 3, 4) )
                            ^
    SyntaxError: invalid syntax

As you can see, adding the parens makes this work:

    >>> map( str(x) given (x), (1, 2, 3, 4) )
    ['1', '2', '3', '4']

More fun with "map":

    >>> map( str(x)*3 given (x), (1, 2, 3, 4) )
    ['111', '222', '333', '444']

Here's an example that uses the **args syntax:

    >>> a = (("%s=%s" % pair for pair in kwargs.items()) given **kwargs)
    >>> list( a(color="red") )
    ['color=red']
    >>> list( a(color="red", sky="blue") )
    ['color=red', 'sky=blue']

I have to say, the more I use it, the more I like it, but I'm sure that 
this is just a personal taste issue. It looks a lot more natural to me 
than lambda.

I should also mention that I resisted the temptation to make the 'given' 
keyword an optional generator suffix as in "(a for a in l given l). As I 
started working with the code, I started to realize that generators and 
closures, although they have some aspects in common, are very different 
beasts and should not be conflated lightly. (Plus the implementation 
would have been messy. I took that as a clue :))

Anyway, if anyone wants to play around with the patch, it is rather 
small - a couple of lines in Grammar, and a small new function in ast.c, 
plus a few mods to other functions to get them to call it. The context 
diff is less than two printed pages. I can post it somewhere if people 
are interested.

Anyway, I am not going to lobby for a language change or write a PEP 
(unless someone asks me to.) I just wanted to throw this out there and 
see what people think of it. I definately don't want to start a flame 
war, although I suspect I already have :/

Now I can stop thinking about this and go back to my TurboGears-based 
Thesaurus editor :)

-- Talin



More information about the Python-Dev mailing list