[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