A critic of Guido's blog on Python's lambda
7 answers - 569 bytes -

Alex Martelli wrote:
I cannot conceive of one. Wherever within a statement I could write the
expression
lambda <args>: body
I can *ALWAYS* obtain the identical effect by picking an otherwise
locally unused identifier X, writing the statement
def X(<args>): body
and using, as the expression, identifier X instead of the lambda.
This is true, but with lambda it is easier to read:
Would be interesting to see how this would look like in Python or some of
the other languages to which this troll thread was posted :-)
No.1 | | 1486 bytes |
| 
Frank Buss <fb (AT) frank-buss (DOT) dewrote:
Alex Martelli wrote:
I cannot conceive of one. Wherever within a statement I could write the
expression
lambda <args>: body
I can *ALWAYS* obtain the identical effect by picking an otherwise
locally unused identifier X, writing the statement
def X(<args>): body
and using, as the expression, identifier X instead of the lambda.
This is true, but with lambda it is easier to read:
Would be interesting to see how this would look like in Python or some of
the other languages to which this troll thread was posted :-)
Sorry, but I just don't see what lambda is buying you here. Taking just
one simple example from the first page you quote, you have:
(defun blank ()
"a blank picture"
(lambda (a b c)
(declare (ignore a b c))
'()))
which in Python would be:
def blank():
" a blank picture "
return lambda a, b, c: []
while a named-function variant might be:
def blank():
def blank_picture(a, b, c): return []
return blank_picture
Where's the beef, really? I find the named-function variant somewhat
more readable than the lambda-based variant, but even if your
preferences are the opposite, this is really such a tiny difference that
I can't see why so many bits should gets wasted debating it (perhaps
it's one of Parkinson's Laws at work).
Alex
No.2 | | 852 bytes |
| 
Alex Martelli wrote:
Sorry, but I just don't see what lambda is buying you here. Taking just
one simple example from the first page you quote, you have:
(defun blank ()
"a blank picture"
(lambda (a b c)
(declare (ignore a b c))
'()))
You are right, for this example it is not useful. But I assume you need
something like lambda for closures, e.g. from the page
:
(defun black-white (&key function limit)
(lambda (x y)
(if ((funcall function x y) limit)
1.0
0.0)))
This function returns a new function, which is parametrized with the
supplied arguments and can be used later as building blocks for other
functions and itself wraps input functions. I don't know Python good
enough, maybe closures are possible with locale named function definitions,
too.
No.3 | | 1310 bytes |
| 
Frank Buss <fb (AT) frank-buss (DOT) dewrote:
Alex Martelli wrote:
Sorry, but I just don't see what lambda is buying you here. Taking just
one simple example from the first page you quote, you have:
(defun blank ()
"a blank picture"
(lambda (a b c)
(declare (ignore a b c))
'()))
You are right, for this example it is not useful. But I assume you need
something like lambda for closures, e.g. from the page
Wrong and unfounded assumption.
:
(defun black-white (&key function limit)
(lambda (x y)
(if ((funcall function x y) limit)
1.0
0.0)))
This function returns a new function, which is parametrized with the
supplied arguments and can be used later as building blocks for other
functions and itself wraps input functions. I don't know Python good
enough, maybe closures are possible with locale named function definitions,
too.
They sure are, I gave many examples already all over the thread. There
are *N* semantic advantages for named vs unnamed functions in Python.
Not sure what the &key means here, but omitting that
def black_white(function, limit):
def result(x,y):
if function(x, y) limit: return 1.0
else: return 0.0
return result
Alex
No.4 | | 485 bytes |
| 
Alex Martelli wrote:
Not sure what the &key means here, but omitting that
def black_white(function, limit):
def result(x,y):
if function(x, y) limit: return 1.0
else: return 0.0
return result
&key is something like keyword arguments in Python. And looks like you are
right again (I've tested it in Pyhton) and my assumption was wrong, so the
important thing is to support closures, which Python does, even with local
function definitions.
No.5 | | 3675 bytes |
| 
There are *N* semantic advantages for named vs unnamed functions in Python.
I feel that this conversation has glanced off the point. Let me try a
new approach:
There is the Pythonic way (whatever that is), and then The Lisp Way. I
don't know what the former is, but it has something to do with
indentation, and the (meaningless to me*) phrase "It fits your mind."
The Lisp way is quite specific: Pure Compositionality. Compositionality
encompasses and defines all aspects of Lisp, from the parens to
functional style to fundamental recursion to lambda, and even the
language itself is classically composed from the bottom up, and
compositionality enables us to create new complete languages nearly
trivially.
How this concept plays into the current conversation is not subtle:
LAMBDA forms server to directly modify the forms in which they appear.
SRT is the example that comes to mind for me. If one says: (sort
#'(lambda (a b) )) [I realize that the #' is optional, I use it here
for emphasis that there is a function being formed.] the lambda form
composes, with sort, a new type of sort -- a sort of type <whatever the
lambda function does>. Thus, the semantics of this form are localized
to the sort expression, and do not leave it -- they are, indeed,
conceptually a part of the sort expression, and to require it/them to
be moved outside and given a name breaks the conceptual
compositionality -- that is, the compositional locality of the form.
Similarly, parens and the functional fact that every form returns a
value provide compositional locality and, perhaps more importantly in
practice, compositional *mobility* -- so that, pretty much anywhere in
Lisp where you need an argument, you can pick up a form and drop it in.
[Macros often break this principle, I'll get to those in a moment.]
This is something that no other language (except some dead ones, like
APL) were able to do, and these provide incredible conceptual
flexibility -- again, I'll use the term "mobility" -- one can, in most
cases, literally move code as though it were a closed concept to
anywhere that that concept is needed.
Macros, as I have said, bear a complex relationship to this concept of
composition mobility and flexibility. The iteration macro, demonstrated
elsewhere in this thread, is an excellent example. But macros are more
subtly related to compositionality, and to the present specific
question, because, as you yourself said: All you need to do is make up
a name that isn't usedBut how is one to find a name that isn't used
if one has macros? [Actually, in Lisp, even if we didn't have lambda we
could do this by code walking, but I'll leave that aside, because
Python can't do that, nor can it do macros.]
I do not hesitate to predict that Python will someday sooner than later
recognize the value of compositional flexibility and mobility, and that
it will struggle against parentheses and lambdas, but that in the end
it will become Lisp again. They all do, or die.
[*] BA - Biographical Annotation: Yeah, I've programmed all those
things too for years and years and years. I also have a PhD in
cognitive psychology from CMU, where I worked on how people learn
complex skills, and specifically programming. When I say that "fits
your brain" is meaningless to me, I mean that in a technical sense:
If it had any meaning, I, of all people, would know what it means;
meaning that I know that it doesn't mean anything at all.
No.6 | | 486 bytes |
| 
7 May 2006 13:35:20 -0700, JShrager (AT) gmail (DOT) com declaimed the following
in comp.lang.python:
I do not hesitate to predict that Python will someday sooner than later
recognize the value of compositional flexibility and mobility, and that
it will struggle against parentheses and lambdas, but that in the end
it will become Lisp again. They all do, or die.
In 20 years Python will be indistinguishable from FRTRAN, and
miles away from LISP <G>
No.7 | | 1783 bytes |
| 
Frank Buss <fb (AT) frank-buss (DOT) dewrote:
Alex Martelli wrote:
Not sure what the &key means here, but omitting that
def black_white(function, limit):
def result(x,y):
if function(x, y) limit: return 1.0
else: return 0.0
return result
&key is something like keyword arguments in Python. And looks like you are
Ah, thanks.
right again (I've tested it in Pyhton) and my assumption was wrong, so the
important thing is to support closures, which Python does, even with local
function definitions.
We do appear to entirely agree. In Python <= 2.4, where if is just a
statement (not an expression), you'd need some trick to get this effect
with a lambda, e.g.:
def black_white(function, limit, key=None):
return lambda x,y: 1.0 * (function(x,y) limit)
assuming it's important to get a float result -- the operator per se
returns an int, so you can call float() on it, or multiply it by 1.0,
etc -- if you had two arbitrary colors, e.g.
def two_tone(function, limit, key=None, low=0.0, high=1.0):
return lambda x,y: (low, high)[function(x,y) limit]
which is a pretty obscure alternative. In Python >= 2.5, an if
expression has been added, but I'll leave you to judge if it's actually
an improvement (sigh):
def two_tone(function, limit, key=None, low=0.0, high=1.0):
return lambda x,y: high if function(x,y) limit else low
Personally, I'd rather use the named-function version. Anyway, they're
all semantically equivalent (sigh), and the key point is that the
semantics (building and returning functions on the fly) IS there,
whether the functions are named or unnamed, as we agree.
Alex