map, filter, reduce, lambda
Given the recent sentiment expressed about Python's various functional builtins, I suspect they will all be absent in Py3k. Skip
Skip Montanaro
Given the recent sentiment expressed about Python's various functional builtins, I suspect they will all be absent in Py3k.
Arrrgghhh!! Nooooo!! Don't take away my lambdas!!! They're far too useful for little callback snippets. -- <a href="http://www.tuxedo.org/~esr/">Eric S. Raymond</a>
Skip Montanaro wrote:
Given the recent sentiment expressed about Python's various functional builtins, I suspect they will all be absent in Py3k.
Really absent? I suspect they will exist as a Python function builtin surrogate for compatibility. This allows to continue using them and can be optimized away, but frees code space for other stuff with higher priority to be coded in C. ciao - chris -- Christian Tismer :^) mailto:tismer@tismer.com Mission Impossible 5oftware : Have a break! Take a ride on Python's Johannes-Niemeyer-Weg 9a : *Starship* http://starship.python.net/ 14109 Berlin : PGP key -> http://wwwkeys.pgp.net/ work +49 30 89 09 53 34 home +49 30 802 86 56 pager +49 173 24 18 776 PGP 0x57F3BF04 9064 F4E1 D754 C2FF 1619 305B C09C 5A3B 57F3 BF04 whom do you want to sponsor today? http://www.stackless.com/
On Thu, Jan 02, 2003, Skip Montanaro wrote:
Given the recent sentiment expressed about Python's various functional builtins, I suspect they will all be absent in Py3k.
If map() goes, we need a replacement:
a = [8, 3, 5, 11] b = ('eggs', 'spam') zip(a,b) [(8, 'eggs'), (3, 'spam')] map(None, a, b) [(8, 'eggs'), (3, 'spam'), (5, None), (11, None)]
Maybe zip() should take a "pad" keyword argument? -- Aahz (aahz@pythoncraft.com) <*> http://www.pythoncraft.com/ "There are three kinds of lies: Lies, Damn Lies, and Statistics." --Disraeli
If map() goes, we need a replacement:
a = [8, 3, 5, 11] b = ('eggs', 'spam') zip(a,b) [(8, 'eggs'), (3, 'spam')] map(None, a, b) [(8, 'eggs'), (3, 'spam'), (5, None), (11, None)]
Maybe zip() should take a "pad" keyword argument?
Only if there's every anybody who needs that feature of map(). --Guido van Rossum (home page: http://www.python.org/~guido/)
"GvR" == Guido van Rossum
writes:
>> should take a "pad" keyword argument? GvR> Only if there's every anybody who needs that feature of GvR> map(). We talked about adding a pad argument to zip() at the time, but rejected it as yagni. And if fact, since then ihnni. -Barry
On Thu, Jan 02, 2003 at 12:54:35PM -0500, Guido van Rossum wrote:
If map() goes, we need a replacement:
a = [8, 3, 5, 11] b = ('eggs', 'spam') zip(a,b) [(8, 'eggs'), (3, 'spam')] map(None, a, b) [(8, 'eggs'), (3, 'spam'), (5, None), (11, None)]
Maybe zip() should take a "pad" keyword argument?
Only if there's every anybody who needs that feature of map().
FWIW, exarkun:~/projects/python$ grep -r "map(None," ./ -r | wc -l 41 I'm more worried about lambda going away, though. Is: class Foo: def setupStuff(self): def somethingOne(): return self.something(1) registerStuff('1', somethingOne) really preferable to: class Foo: def setupStuff(self): registerStuff('1', lambda: self.something(1)) Nested scopes make it better than it once would have been, but I can still see a lot of my GUI code getting a lot hairier if I don't have lambda at my disposal. I don't see a decent way to implement it in Python, either. Jp
Jp Calderone wrote:
class Foo: def setupStuff(self): registerStuff('1', lambda: self.something(1))
Nested scopes make it better than it once would have been, but I can still see a lot of my GUI code getting a lot hairier if I don't have lambda at my disposal. I don't see a decent way to implement it in Python, either.
For the specific example, you can easily do without lambda: from functional import bind class Foo: def setupStuff(self): registerStuff('1', bind(self.something, 1)) where bind could be defined as class bind: def __init__(self, f, *args): self.f = f self.args = args def __call__(self, *moreargs): return self.f(*(args+moreargs)) Regards, Martin
I'm more worried about lambda going away, though. Is:
class Foo: def setupStuff(self): def somethingOne(): return self.something(1) registerStuff('1', somethingOne)
really preferable to:
class Foo: def setupStuff(self): registerStuff('1', lambda: self.something(1))
Nested scopes make it better than it once would have been, but I can still see a lot of my GUI code getting a lot hairier if I don't have lambda at my disposal. I don't see a decent way to implement it in Python, either.
Good question. Would this be acceptable? class Foo: def setupStuff(self): registerStuff('1', curry(self.something, 1)) curry() is something you could write now, and seems mildly useful. Of course it's more functional cruft, but I'd rather add more "function algebra" than more APL-style operations. --Guido van Rossum (home page: http://www.python.org/~guido/)
On Thu, Jan 02, 2003 at 01:53:34PM -0500, Guido van Rossum wrote:
I'm more worried about lambda going away, though. Is: [snip example]
class Foo: def setupStuff(self): registerStuff('1', curry(self.something, 1))
curry() is something you could write now, and seems mildly useful. Of course it's more functional cruft, but I'd rather add more "function algebra" than more APL-style operations.
True (and I have implemented curry ;). For this kind of thing, I think it's a totally acceptable replacement. But, another example: sometimes you want to conform to a particular interface, but return a constant or invoke another function with only some of the arguments provided. For example, overriding a Request object's getSession in the case where it hasn't got one: request.getSession = lambda interface = None: None Or in Tk, I use "lambda x: 'break'" as a callback, to indicate that an event should be propagated no further. Or if I want only part of a result passed on to a later callback, or want it transformed somehow (or both), I often use something like: lambda result: tuple(result[0]) Obviously any of the could simply be a function created with 'def', but it seems so much less elegant that way: more lines of code are required, information about what's happening is moved away from where it happens to some potentially distant location, *and* worst of all, I have to come up with a name for these new functions ;) Losing lambda would be a huge inconvenience, but probably not a crippling lose. I would be happier if there were a better reason than that some people don't like functional elements or that it might save a few kilobytes in the interpreter core (if it would save more than a few, excuse me, I haven't investigated this part of the interpreter yet). Jp
Guido> curry() is something you could write now, and seems mildly Guido> useful. Of course it's more functional cruft, but I'd rather Guido> add more "function algebra" than more APL-style operations. I'm presently working on a pattern-matching library that uses lambda as a way of representing circular data structures. The basic idea is that I build up these data structures from components, and if one of those components is a function, it signifies a request to call that function while the data structure is being traversed. Hence the circularity. Here's an example that defines a pattern that matches a parenthesis-balanced string: bal = Arbno(Notany("()") | "(" + Call(lambda: bal) + ")") I really, really don't want to have to define a separate function each time I write one of these expressions. -- Andrew Koenig, ark@research.att.com, http://www.research.att.com/info/ark
I'm presently working on a pattern-matching library that uses lambda as a way of representing circular data structures. The basic idea is that I build up these data structures from components, and if one of those components is a function, it signifies a request to call that function while the data structure is being traversed. Hence the circularity.
Here's an example that defines a pattern that matches a parenthesis-balanced string:
bal = Arbno(Notany("()") | "(" + Call(lambda: bal) + ")")
I really, really don't want to have to define a separate function each time I write one of these expressions.
If they really are all that simple and for this specific purpose, I wonder if you can't embed a reference to a variable directly, e.g. bal = Arbno(Notany("()") | "(" + Local("bal") + ")") --Guido van Rossum (home page: http://www.python.org/~guido/)
Guido> If they really are all that simple and for this specific purpose, I Guido> wonder if you can't embed a reference to a variable directly, e.g. Guido> bal = Arbno(Notany("()") | "(" + Local("bal") + ")") I will sometimes want the lambda to yield something more complicated than a variable. I also use lambda heavily in the implementation of the library. A sample code fragment: def evaluate(self): data, end = \ self.pat.traverse(lambda obj, *args: obj.evaluate(self.seq, *args), self.begin, self.data) return data Yes, I realize I could rewrite it this way: def evaluate(self): def foo(obj, *args): return obj.evaluate(self.seq, *args) data, end = self.pat.traverse(foo, self.begin, self.data) return data but I'd rather not. (Actually, what I really want here is to be able to write this: def evaluate(self): data, end = self.pat.traverse(virtual evaluate, self.begin, self.data) return data where "virtual evaluate" is a made-up notation for "the evaluate method of whatever object I wind up getting my hands on.")
I'll have to think about this more. lambda is annoying to me because it adds so little compared to writing a one-line def. But it makes sense for certain programming styles. --Guido van Rossum (home page: http://www.python.org/~guido/)
Guido van Rossum
I'll have to think about this more. lambda is annoying to me because it adds so little compared to writing a one-line def. But it makes sense for certain programming styles.
Indeed it does. There's a reason old LISP-heads like me have a tendency to snarl "You'll take my lambdas when you pry them from my cold, dead fingers", and it's not just orneriness. It comes a view of the world in which the property of "having a name" is orthogonal to the property of "being a function". If that's one's view of the world, writing lots of little one-line defs is not just annoying, it's a kind of coincidential cohesion or pollution. -- <a href="http://www.tuxedo.org/~esr/">Eric S. Raymond</a>
Guido> I'll have to think about this more. lambda is annoying to me Guido> because it adds so little compared to writing a one-line def. Guido> But it makes sense for certain programming styles. Yes -- there are times when notational compactness greatly aids mental chunking. And of course there are other times when notational compactness stands in the way of comprehension. Sometimes a single notation can do both at once, depending on the reader's prior experience. Consider the following C statement: *p++ = *q++; If you're an experienced programmer, the meaning of this statement is immediately obvious; if not, it's obfuscation. Similarly, map(lambda x: x**2, data) is really obvious to some people, and confusing to others, as is [x**2 for x in data] -- Andrew Koenig, ark@research.att.com, http://www.research.att.com/info/ark
From: "Guido van Rossum"
I'm presently working on a pattern-matching library that uses lambda as a way of representing circular data structures. The basic idea is that I build up these data structures from components, and if one of those components is a function, it signifies a request to call that function while the data structure is being traversed. Hence the circularity.
Here's an example that defines a pattern that matches a parenthesis-balanced string:
bal = Arbno(Notany("()") | "(" + Call(lambda: bal) + ")")
I really, really don't want to have to define a separate function each time I write one of these expressions.
If they really are all that simple and for this specific purpose, I wonder if you can't embed a reference to a variable directly, e.g.
bal = Arbno(Notany("()") | "(" + Local("bal") + ")")
I find that playing with callers' stack frame is more evil than lambda :) Although this whole thing is about Py3K, it seems rather a silly "waste" of time. I don't know how lambda really partition the user base. I know some are vocally against it as kind of sin. But I find as easy to argument about how much a conceptual dead-weight lambda is, a waste of precious users' memory/learning capabilities and the non purity of lambda, as to argument that "practicality beats purity" and yes we have lambda but we are not a Lisp, and yes it's limited (crippled in Lisper's eyes) but for that just fine and pythonic. don't-sweat-ly y'rs
But I find as easy to argument about how much a conceptual dead-weight lambda is, a waste of precious users' memory/learning capabilities and the non purity of lambda, as to argument that "practicality beats purity" and yes we have lambda but we are not a Lisp, and yes it's limited (crippled in Lisper's eyes) but for that just fine and pythonic.
Good point. PBP beats TOOWTDI. :-) BTW, I don't think it's crippled any more -- we now have nested scopes, remember. --Guido van Rossum (home page: http://www.python.org/~guido/)
From: "Guido van Rossum"
But I find as easy to argument about how much a conceptual dead-weight lambda is, a waste of precious users' memory/learning capabilities and the non purity of lambda, as to argument that "practicality beats purity" and yes we have lambda but we are not a Lisp, and yes it's limited (crippled in Lisper's eyes) but for that just fine and pythonic.
Good point. PBP beats TOOWTDI. :-)
BTW, I don't think it's crippled any more -- we now have nested scopes, remember.
just expressions and no statements, that's quite crippled for a Lisper :-). The whole statement/expression distinction is evil for "them", enforce readability for "us".
Guido van Rossum
Good point. PBP beats TOOWTDI. :-)
Is that a ukase of the Tsar? I'll remember it. :-)
BTW, I don't think it's crippled any more -- we now have nested scopes, remember.
Yes, that helps a lot. In particular, it greatly strengthens lambda for its practical role in anonymous callbacks for GUIs. There is still the problem thatlambdas can only capture expressions, not statements. But I've given up on that one, alas. -- <a href="http://www.tuxedo.org/~esr/">Eric S. Raymond</a>
Guido van Rossum
: Good point. PBP beats TOOWTDI. :-)
Is that a ukase of the Tsar? I'll remember it. :-)
No, just an ad-hoc observation in this case. --Guido van Rossum (home page: http://www.python.org/~guido/)
Guido van Rossum wrote:
But I find as easy to argument about how much a conceptual dead-weight lambda is, a waste of precious users' memory/learning capabilities and the non purity of lambda, as to argument that "practicality beats purity" and yes we have lambda but we are not a Lisp, and yes it's limited (crippled in Lisper's eyes) but for that just fine and pythonic.
Good point. PBP beats TOOWTDI. :-)
BTW, I don't think it's crippled any more -- we now have nested scopes, remember.
... and they were added just for this reason. I was never a fan of lambda -- a simple def is just as readable, but the complexity that nested scopes added to the Python interpreter just to make lambda users happy has to be worth something. If you rip out lambda now, you might as well go back to the good old three step lookup scheme. As for the other APIs in the subject line: I really don't understand what this discussion is all about. map(), filter(), reduce() have all proven their usefulness in the past. Anyway, just my 2 cents, -- Marc-Andre Lemburg CEO eGenix.com Software GmbH _______________________________________________________________________ eGenix.com -- Makers of the Python mx Extensions: mxDateTime,mxODBC,... Python Consulting: http://www.egenix.com/ Python Software: http://www.egenix.com/files/python/
"MAL" == mal
writes:
BTW, I don't think it's crippled any more -- we now have nested scopes, remember.
MAL> ... and they were added just for this reason. One reason among many, yes. I've certainly written a lot of code in the last year or two that exploits nested scopes using nested functions. It's used in a lot of little corners of ZODB, like the test suite. MAL> I was never a fan MAL> of lambda -- a simple def is just as readable The seems to be a clear line here. Some folks think a def is just as readable, some folks think it is unnecessarily tedious to add a bunch of statements and invent a name. MAL> As for the other APIs in the subject line: I really don't MAL> understand what this discussion is all about. map(), filter(), MAL> reduce() have all proven their usefulness in the past. Useful enough to be builtins? They could just as easily live in a module. They could even be implemented in Python if performance weren't a big issue. Jeremy
Jeremy Hylton wrote:
"MAL" == mal
writes: BTW, I don't think it's crippled any more -- we now have nested scopes, remember.
MAL> ... and they were added just for this reason.
One reason among many, yes.
I've certainly written a lot of code in the last year or two that exploits nested scopes using nested functions. It's used in a lot of little corners of ZODB, like the test suite.
MAL> I was never a fan MAL> of lambda -- a simple def is just as readable
The seems to be a clear line here. Some folks think a def is just as readable, some folks think it is unnecessarily tedious to add a bunch of statements and invent a name.
MAL> As for the other APIs in the subject line: I really don't MAL> understand what this discussion is all about. map(), filter(), MAL> reduce() have all proven their usefulness in the past.
Useful enough to be builtins? They could just as easily live in a module. They could even be implemented in Python if performance weren't a big issue.
I think that if they were added to Python now, they'd probably better be off in a separate "functional" module; perhaps we should move them there and only keep the reference in the builtins to them ?! -- Marc-Andre Lemburg CEO eGenix.com Software GmbH _______________________________________________________________________ eGenix.com -- Makers of the Python mx Extensions: mxDateTime,mxODBC,... Python Consulting: http://www.egenix.com/ Python Software: http://www.egenix.com/files/python/
M.-A. Lemburg wrote: ...
I think that if they were added to Python now, they'd probably better be off in a separate "functional" module; perhaps we should move them there and only keep the reference in the builtins to them ?!
That's what I'm proposing. ciao - chris -- Christian Tismer :^) mailto:tismer@tismer.com Mission Impossible 5oftware : Have a break! Take a ride on Python's Johannes-Niemeyer-Weg 9a : *Starship* http://starship.python.net/ 14109 Berlin : PGP key -> http://wwwkeys.pgp.net/ work +49 30 89 09 53 34 home +49 30 802 86 56 pager +49 173 24 18 776 PGP 0x57F3BF04 9064 F4E1 D754 C2FF 1619 305B C09C 5A3B 57F3 BF04 whom do you want to sponsor today? http://www.stackless.com/
Guido van Rossum wrote:
But I find as easy to argument about how much a conceptual dead-weight lambda is, a waste of precious users' memory/learning capabilities and the non purity of lambda, as to argument that "practicality beats purity" and yes we have lambda but we are not a Lisp, and yes it's limited (crippled in Lisper's eyes) but for that just fine and pythonic.
Good point. PBP beats TOOWTDI. :-)
BTW, I don't think it's crippled any more -- we now have nested scopes, remember.
I was never against lambda. map, reduce, filter, apply: They are just abstractions which take a function and let them work on arguments in certain ways. They are almost obsolete now since they can be replaced by powerful constructs like comprehensions and the very cute asterisk calls. lambda, on the other hand, *is* a powerful construct, since it provides an ad-hoc functional value. It is not restricted by having to be declared in a syntactical proper place. I think this is the major point. One of Python's strengths is that declarations are seldom needed, almost all objects can be created in-place. Not so with defs: They enforce a declaration before use, while lambda denotes a functional value. I'd even think to extend and generalize lambda. ciao - chris -- Christian Tismer :^) mailto:tismer@tismer.com Mission Impossible 5oftware : Have a break! Take a ride on Python's Johannes-Niemeyer-Weg 9a : *Starship* http://starship.python.net/ 14109 Berlin : PGP key -> http://wwwkeys.pgp.net/ work +49 30 89 09 53 34 home +49 30 802 86 56 pager +49 173 24 18 776 PGP 0x57F3BF04 9064 F4E1 D754 C2FF 1619 305B C09C 5A3B 57F3 BF04 whom do you want to sponsor today? http://www.stackless.com/
It just occurred to me one reason I'm not enamored of lambdas is that the keyword "lambda" has no mnemonic meaning at all the way for example that "def" is suggestive of "define". I suspect most programmers have never studied the Lambda Calculus, and other than perhaps during a brief exposure to Lisp will never have encountered the term at all. (Remember, Andrew & Eric are hardly poster children for your run-of-the-mill programmers.) Somewhat tongue-in-cheek here, and definitely not suggesting this for Python 2.x, but is there perhaps a little bit of line noise we can appropriate from Perl to replace the lambda construct? Lambda's brevity seems to be its major strength. Is there a reason def couldn't have been reused in this context? perhaps-i-should-write-a-pep-ly, y'rs, Skip
Somewhat tongue-in-cheek here, and definitely not suggesting this for Python 2.x, but is there perhaps a little bit of line noise we can appropriate from Perl to replace the lambda construct? Lambda's brevity seems to be its major strength. Is there a reason def couldn't have been reused in this context?
You couldn't reuse def, because lambda can start an expression which can occur at the start of a line, so a line starting with def would be ambiguous (Python's parser is intentionally simple-minded and doesn't like having to look ahead more than one token). Moreover, def is short for define, and we don't really define something here. Maybe callback would work? I'd add the parentheses back to the argument list for more uniformity with def argument lists, so we'd get: lst.sort(callback(a, b): cmp(a.lower(), b.lower())) (Yes, I'm familiar with Schwartzian transform, but it's not worth the complexity if the list is short.) But I still think that to the casual programmer a two-liner looks better: def callback(a, b): return cmp(a.lower(), b.lower()) lst.sort(callback) Maybe the Lisp folks are more tolerant of nested parentheses. :-) --Guido van Rossum (home page: http://www.python.org/~guido/)
>> Is there a reason def couldn't have been reused in this context?
Guido> You couldn't reuse def, because lambda can start an expression
Guido> which can occur at the start of a line, so a line starting with
Guido> def would be ambiguous (Python's parser is intentionally
Guido> simple-minded and doesn't like having to look ahead more than one
Guido> token).
I'll leave that gauntlet thrown, since I have no interest in rewriting
Python's parser. Maybe it will spark John Aycock's interest though. ;-)
Guido> Moreover, def is short for define, and we don't really define
Guido> something here.
Yes we do, we define a function, we just don't associate it with a name. In
theory the following two function definitions could be equivalent:
def f(a,b):
return a+b
f = def(a,b): a+b
and except for that pesky two-token lookahead would be possible.
Guido> Maybe callback would work? I'd add the parentheses back to the
Guido> argument list for more uniformity with def argument lists, so
Guido> we'd get:
I agree about adding back the parens, but not the name. Lambdas are used
for more than callbacks.
Returning to a previous gauntlet I threw which nobody picked up, I came up
with this replacement for lambda. I call it "lamduh".
import new
import sys
def lamduh(args, expr):
argstr = ", ".join(map(str, args))
uplevel = sys._getframe(1) # for you tcl fans...
g = {}
exec "def f(%s): return (%s)" % (argstr, expr) in g
f = g['f']
return new.function(f.func_code, uplevel.f_globals, "<lambda>",
f.func_defaults, f.func_closure)
And here's some example usage:
>>> f = lamduh.lamduh((), "bal")
>>> f
Skip Montanaro wrote:
Yes we do, we define a function, we just don't associate it with a name. In theory the following two function definitions could be equivalent:
def f(a,b): return a+b
f = def(a,b): a+b
and except for that pesky two-token lookahead would be possible.
Huh? Where's two token lookahead required? The token after "def" is either a word, or its "(". Doesn't look very ambiguous to me! Doesn't even require one-token lookahead, does it? Cheers, Ben. -- http://www.apache-ssl.org/ben.html http://www.thebunker.net/ "There is no limit to what a man can do or how far he can go if he doesn't mind who gets the credit." - Robert Woodruff
On Thu, Jan 02, 2003 at 08:52:18PM -0500, Guido van Rossum wrote:
You couldn't reuse def, because lambda can start an expression which can occur at the start of a line, so a line starting with def would be ambiguous (Python's parser is intentionally simple-minded and doesn't like having to look ahead more than one token).
Ah. I knew I was missing something when I made this suggestion (in a different subthread). Could the parser be taught that def-at-start-of-line is always good old fashioned funcdef instead of anon_funcdef (my name), since the statement def(): None is a useless one (you can't call it, you can't assign it, ..)? (And you could write the statement '(def(): None)' if you were really adamant that you wanted to perform that particular useless thing) The conflict may exist in the grammar, but could be resolved in a particular way in the parser. Or maybe there's even a clever way to write the grammar to make the ambiguity go away. Something along the lines of simple_stmt: expr_stmt_nodef | ... expr_stmt_nodef: testlist_nodef ... testlist_nodef: test_nodef (',' test)* [','] test_nodef: and_test ('or' and_test)* I think the complications stop cascading at that point. Jeff
"SM" == Skip Montanaro
writes:
SM> Somewhat tongue-in-cheek here, and definitely not suggesting SM> this for Python 2.x, but is there perhaps a little bit of line SM> noise we can appropriate from Perl to replace the lambda SM> construct? Lambda's brevity seems to be its major strength. SM> Is there a reason def couldn't have been reused in this SM> context? For Py3K, I might suggest "anon" instead of lambda, especially if the construct were expanded to allow statements. -Barry
Barry A. Warsaw
For Py3K, I might suggest "anon" instead of lambda, especially if the construct were expanded to allow statements.
Speaking as one of the unregenerate LISP-heads, I don't care what it's called as long as it's *there*. -- <a href="http://www.tuxedo.org/~esr/">Eric S. Raymond</a>
"ESR" == Eric S Raymond
writes:
>> For Py3K, I might suggest "anon" instead of lambda, especially >> if the construct were expanded to allow statements. ESR> Speaking as one of the unregenerate LISP-heads, I don't care ESR> what it's called as long as it's *there*. Oh well if that's the case, then I'll suggest floob_boober_bab_boober_bubs. :) -Barry
"JH" == Jeremy Hylton
writes:
"BAW" == Barry A Warsaw
writes:
BAW> For Py3K, I might suggest "anon" instead of lambda, BAW> especially if the construct were expanded to allow BAW> statements. JH> The problem with anon is that the name doesn't suggest a JH> function. And "def" does? <wink>. Maybe we should call it "abc" since creating a function comes before defining the name for the function. It's also a nod to Python's historical roots. :) anondef-ly y'rs, -Barry
On Thu, Jan 02, 2003 at 07:08:11PM -0600, Skip Montanaro wrote:
It just occurred to me one reason I'm not enamored of lambdas is that the keyword "lambda" has no mnemonic meaning at all the way for example that "def" is suggestive of "define". I suspect most programmers have never studied the Lambda Calculus,
And I suspect most programmers have never heard of George Boole. The concepts of boolean and lambda and their strange names are both equally alien to newbies. Some people happen to know one but not the other based on their programming background, that's all. I can be very particular about terminology. I have been known to spend half an hour with a thesaurus trying to find a term for a concept that is suggestive of its semantics yet not overloaded with other meanings that may lead to wrong assumptions. But when that fails, I sometimes choose a name that is intentionally meaningless. I think the name 'lambda' serves that purpose quite well I don't think any mnemonic name could possibly convey what lambda really means. Cute line noise like * and ** calls is no better. As Bill Bumgarner pointed out, a name at least gives you something so you can look up in the documentation. I won't mind too much if the map, filter, reduce and apply builtins would be gone in some future version. You can always import them from the __past__ for compatibility. But let the lambda stay. Oren
[Skip Montanaro]
It just occurred to me one reason I'm not enamored of lambdas is that the keyword "lambda" has no mnemonic meaning at all the way for example that "def" is suggestive of "define". I suspect most programmers have never studied the Lambda Calculus, and other than perhaps during a brief exposure to Lisp will never have encountered the term at all. (Remember, Andrew & Eric are hardly poster children for your run-of-the-mill programmers.)
We might merely consider that `lambda' is not for children. :-). Most Lisp users have never studied Lambda Calculus either, and this does not create a problem to them for using it. And lambda expressions allow for statements, at least from a semantic viewpoint. So, if Python `lambda' were ever extended to include statements, I see nothing especially shocking with calling the result `lambda'. I'm not especially prone for `lambda' in Python, but if it stays anyway, why not just stick with `lambda'? What do we gain by changing the keyword? Some might question if it was judicious or not adding `lambda' to Python, but the questioning might be more related to the existence or specifications of anonymous functions than to the choice of the keyword, and changing the keyword will likely not get rid of the questioning. -- François Pinard http://www.iro.umontreal.ca/~pinard
I think this is the major point. One of Python's strengths is that declarations are seldom needed, almost all objects can be created in-place. Not so with defs: They enforce a declaration before use, while lambda denotes a functional value.
You think of a def as a declaration. I don't: to me, it's just an assignment, no more obtrusive than using a variable to hold a subexpression that's too long to comfortably fit on a line. --Guido van Rossum (home page: http://www.python.org/~guido/)
Guido van Rossum wrote:
I think this is the major point. One of Python's strengths is that declarations are seldom needed, almost all objects can be created in-place. Not so with defs: They enforce a declaration before use, while lambda denotes a functional value.
You think of a def as a declaration. I don't: to me, it's just an assignment, no more obtrusive than using a variable to hold a subexpression that's too long to comfortably fit on a line.
I think this is only half of the truth. Sure, a def is an expression. A class is an expression as well, since everything in a Python source file gets executed, with some parts producing immediate output and other parts creating functions, classes and methods. On the other hand, every analysing tool for Python treats classes and functions as declarations, and this is also how people usually think of it. The fact that execution of code that contains a "declaration" results in creating that object, is a somehow elegant implementation detail but doesn't change the fact that people are declaring a function; they are not assigning an expression result to a name. Your argument about using a variable to hold a subexpression that doesn't fit a line does not compare well, because def doesn't give you a chance to write a function body inline. You have to have a name, proper indentation, all of that. ciao - chris -- Christian Tismer :^) mailto:tismer@tismer.com Mission Impossible 5oftware : Have a break! Take a ride on Python's Johannes-Niemeyer-Weg 9a : *Starship* http://starship.python.net/ 14109 Berlin : PGP key -> http://wwwkeys.pgp.net/ work +49 30 89 09 53 34 home +49 30 802 86 56 pager +49 173 24 18 776 PGP 0x57F3BF04 9064 F4E1 D754 C2FF 1619 305B C09C 5A3B 57F3 BF04 whom do you want to sponsor today? http://www.stackless.com/
"Andrew" == Andrew Koenig
writes:
Andrew> I'm presently working on a pattern-matching library that uses Andrew> lambda as a way of representing circular data structures. ... Andrew> Here's an example ... Andrew> bal = Arbno(Notany("()") | "(" + Call(lambda: bal) + ")") That looks very cool. To avoid lambda I suspect you could have Call() take a string ("bal") which is later eval'd in the correct context to get the actual function object to be called. (This eval() could be performed once, caching the result to avoid repeated lookups.) In this particular case, "lambda: bal" is simply deferring evaluation of bal anyway. My observation about map and friends was just that. It seems there is little support for apply, it having already been deprecated. Map and reduce seem iffy. Nobody's stepped up to castigate filter, though I don't recall seeing any defenders either. Lambda seems to be the only one of the bunch with any strong support. It's perfect in those situations where it works, but too limited everywhere else. Couldn't lambda be more-or-less supplanted by a thin wrapper around new.function()? I took a quick crack at it but failed. Probably caffeine or sugar deficit. Skip
Andrew> bal = Arbno(Notany("()") | "(" + Call(lambda: bal) + ")") Skip> That looks very cool. I hope to be able to give a talk about it at the Oxford conference in April.
I hope to be able to give a talk about it at the Oxford conference in April.
I guess you won't make it to PyCon in DC the week before that? --Guido van Rossum (home page: http://www.python.org/~guido/)
I hope to be able to give a talk about it at the Oxford conference in April.
Guido> I guess you won't make it to PyCon in DC the week before that? Hadn't thought that far ahead, actually. Looking at the calendar now, I think there's a good chance I'll be able to make it.
Skip Montanaro
My observation about map and friends was just that. It seems there is little support for apply, it having already been deprecated. Map and reduce seem iffy. Nobody's stepped up to castigate filter, though I don't recall seeing any defenders either. Lambda seems to be the only one of the bunch with any strong support. It's perfect in those situations where it works, but too limited everywhere else.
Speaking for me...I would miss apply() and reduce() very little, and filter() only somewhat -- but losing map() and lambda would be *very* painful. I think that we shouldn't nibble at functional programming piecemeal, though. Either Python is going to support this or it's not. If it's not, shoot 'em all. If it is, I say keep 'em all and add curry(). I'm in favor of supporting functional programming. This is not mere zealotry on my part; I can imagine taking the opposite position if the complexity or implementation cost of those primitives were high. But my impression is that it is not. -- <a href="http://www.tuxedo.org/~esr/">Eric S. Raymond</a>
Eric> Speaking for me...I would miss apply() and reduce() very little, and filter() Eric> only somewhat -- but losing map() and lambda would be *very* painful. You can write apply, reduce, filter, and map if you want. You can't write lambda if it's not already there. Therefore, I feel more strongly about lambda than about the others.
Eric> Speaking for me...I would miss apply() and reduce() very little, Eric> and filter() only somewhat -- but losing map() and lambda would Eric> be *very* painful. Losing lambda would be more painful than losing map, because you can always write map yourself if you don't have it.
Zack> Apply has been deprecated?! What am I supposed to use instead? You can replace apply(f, args) by f(*args) and apply(f, args, kwds) by f(*args, **kwds).
Jp Calderone
Nested scopes make it better than it once would have been, but I can still see a lot of my GUI code getting a lot hairier if I don't have lambda at my disposal. I don't see a decent way to implement it in Python, either.
Exactly my pragmatic objection. As distinct from my emotional LISP-head reaction, which is "AAAAARRGGHHH!!!" -- <a href="http://www.tuxedo.org/~esr/">Eric S. Raymond</a>
participants (18)
-
"Martin v. Löwis"
-
Aahz
-
Andrew Koenig
-
Anthony Baxter
-
barry@python.org
-
Ben Laurie
-
Christian Tismer
-
Eric S. Raymond
-
Guido van Rossum
-
Jeff Epler
-
Jeremy Hylton
-
Jp Calderone
-
M.-A. Lemburg
-
Oren Tirosh
-
pinard@iro.umontreal.ca
-
Samuele Pedroni
-
Skip Montanaro
-
Zack Weinberg