pep 312 - implicit lambdas idea

I was thinking about a good syntax for implicit lambdas for a while and today I had this idea: make ``_:`` a shortcut for ``lambda _=None:`` For example: map( _: _ + 5, some_list) register_callback( _: True) def apply_transform(..., transform = _:_, ... ): but still addition = lamba x, y: x + y The rationale is that you only want to get rid of lambda keyword to create a *very* simple function, the one that will be called either without parameters or with only one parameter. For everything more complicated, you really should go and write the explicit function signature using lambda. Even though ``:`` could theoretically denote implicit lambda, it's too easy to miss it. The combination ``_:`` is much easier to notice. It also makes explicit that there is at most one parameter and it's name is ``_``. Since it's very short, it can easily be used in a long function call or as a default parameter, as above Your thoughts?

I'd like to use this syntax only in situations of PEP 312, that is, where a colon is prohibited by current grammar. In those situations, writing _: is also prohibited by current grammar so it will be parsed unambiguously. The examples you quoted will not change under my idea, but ``x = (_:_*2)`` would be possible as an alternative. Note that I would be against being able to use ``x = _:_*2``. I think it's better to require either lambda keyword or parentheses for the RHS of the assignment as colon has a well-defined meaning as starting an indented block unless it's inside some brackets. On Fri, Aug 7, 2009 at 4:58 PM, Gerald Britton<gerald.britton@gmail.com> wrote:

On 7 Aug 2009, at 15:08 , ilya wrote:
It's not much of a gain though, some kind of currying for operators might be a more general idea for those cases. Or simply a better lambda syntax (Haskell has a pretty cool one for what it's worth, but it might conflict with the EOL escape thing), but as far as I know previous discussions on the subject have either failed to come up with a viable syntax or failed to get the approval of the community or BDFL.

ilya <ilya.nikokoshev@gmail.com> writes:
I was thinking about a good syntax for implicit lambdas for a while
Why were you thinking of this, and why is it important enough to override “explicit is better than implicit”?
and today I had this idea: make ``_:`` a shortcut for ``lambda _=None:``
-1. The name ‘_’ already sees a lot of use as an identifier. It is in common use as a conventional shortcut to the ‘gettext.gettext’ function. It is also commonly used as a name to bind to a value that is returned from some process but not actually needed. Overloading existing conventions of that valid identifier with this special construct is too much, in my view.
Even though ``:`` could theoretically denote implicit lambda, it's too easy to miss it. The combination ``_:`` is much easier to notice.
I disagree; it is too easy to miss. -- \ “Last year I went fishing with Salvador Dali. He was using a | `\ dotted line. He caught every other fish.” —Steven Wright | _o__) | Ben Finney

My suggestion for a lightweight lambda syntax is args -> expr Examples: map(x -> x + 5, something) d = defauldict(->[]) -- Greg

I notice you said "args" not "arg". How would you parse foo(x, y -> x + y)? Even if the compiler can parse it, how about the human reading the code? If lambda wasn't already there, I could see using (args) -> expr syntax but I think there shouldn't be two ways to do something so simple. If you really want a shorter syntax, the obvious choice is foo(λx, y: x + y). --- Bruce On Fri, Aug 7, 2009 at 5:49 PM, Greg Ewing <greg.ewing@canterbury.ac.nz>wrote:

08-08-2009 Greg Ewing <greg.ewing@canterbury.ac.nz> wrote:
-1 The idea would be nice, but "->" has already another meaning (in a different context -- function annotations -- but it's not a good idea to use the same "operator" for two completely different things, both connected with functions). *j

On Fri, 7 Aug 2009 10:46:40 pm ilya wrote:
[...]
Why would you want to get rid of the lambda keyword? What's the benefit? Is this about saving twelve keystrokes? lambda _=None: versus _: Just how often do you want, or need, to write such a lambda? It seems to me that not only is it a special case you want to break the rules for, which goes against the Zen, but it's an incredibly rare special case. _ as an identifier already has three conventional meanings: (1) In the interactive interpreter, _ is the value of the last expression typed. (2) It is commonly used to mean "I don't care about this value", e.g. t = ("Fred Smith", "123 Fourth Street", "New York", "dog") name, _, _, pet = t (3) It is also often used in internationalization. You want to give it the extra meaning "a default parameter name for lambda when I can't be bothered typing even a single letter name". Because _ is already a valid identifier, this will break code that does this: while _: process() _ = function() if _: print "something" Not the best choice of names, but somebody, somewhere, is doing that, and your suggestion will break their code. Looking at the three examples you gave: map( _: _ + 5, some_list) register_callback( _: True) def apply_transform(..., transform = _:_, ... ): In the first case, I wouldn't use the short-cut form even if it were available. I'd write a lambda that used a more meaningful name. In this case, I'm expecting an int, so I would use n, or a float, so I'd use x. I'd also avoid setting the pointless default: map(lambda x: x+5, some_list) vs map(_: _+5, some_list) Since your suggestion doesn't do precisely what I want, the only reason I would have for using your construct is to save seven keystrokes. Encouraging laziness on the behalf of the programmer is not a good reason for special-casing rare cases. Second case: register_callback( _: True) I assume you're implying that the callback function must take a single argument. In this example, using _ as the parameter name to the lambda makes sense, because it is a "don't care" argument. But if the callback function is documented as always being given a single argument, I would want to know if it was being called without any arguments, so the default value of None is inappropriate and I would avoid using it. Third case: def apply_transform(..., transform = _:_, ... ): I don't think I'd write a function called apply_transform() which made the transformation function optional, let alone buried deep in the middle of a whole lot of extra parameters. (I presume that's what the "..."s are meant to imply.) But putting that aside, I see your intention: a default do-nothing function which appears in a very long parameter list. The problem is that instead of trying to shrink the default value so you can fit all the parameters on a single line, you should make such a complicated function signature more readable by spreading it out: def apply_transform( obj, start, end, # start (inc) and end (exc) positions to apply another_arg, # does something very important I'm sure x=0, y=1, z=2, # more very important arguments transform=( # default null transformation lambda obj=None: obj), frotz=False, # if true, frotz the hymangirator with spangule hymangirator=None, spangule=None, magic=12345, # this needs no documentation namespace={}, flibbertigibbet=None, _private_magic=[] # the caller shouldn't supply this ): (Even better is to avoid such complicated function signatures, but sometimes that's not an option.) So again I'd be very unlikely to use your suggested construct except out of simple can't-be-bothered-to-type-a-dozen-letters laziness. Pandering to that sort of laziness is probably not a good thing. Fundamentally, this suggestion doesn't add expressability to the language, or power. Laziness on it's own is not a good reason for special casing rare cases. If it was a very common case, then *perhaps* you would have an argument for special casing needless verbiage: conciseness (up to a point) is a virtue in a language. That's partly why we have lambdas in the first place, so we can write this: reduce(lambda a,b: (a+b)/2.0, somelist) instead of this: def average(a, b): return (a+b)/2.0 reduce(average, somelist) But this isn't a common case, it's a rare case, and the case you're hoping to replace is pretty concise already. -- Steven D'Aprano

Steven D'Aprano wrote:
Why would you want to get rid of the lambda keyword? What's the benefit?
Is this about saving twelve keystrokes?
It's about conciseness. The only time it makes sense to write a function in-line is when the body is extremely short -- but then it gets swamped by the lambda keyword itself. But I agree that the OP's particular solution is restricted to a case that's too special. My version is completely general -- it can express anything that the existing lambda can express. -- Greg

Thank you and everyone else for insightful posts detailing why my examples don't make a good argument for the syntax. Even though my original suggestion, similarly pep 312, wouldn't break any existing programs and would not lead to ambiguity in 'if _:', I rescind it. However, another reason for implicit lambdas is lazy evaluation. For example, in another thread people discuss "... except ... if/else" conditional statement --- one reason being control expressions evaluate lazily. A function call passing callables currently looks ugly and unreadable: lazy_cond(expr, lambda: expensive(5), lambda: factorial(10**5)) and here 6 keystrokes of 'lambda' word *do* matter. Therefore I hope my unsuccessful proposal will encourage people to find something that works. On Sat, Aug 8, 2009 at 4:21 AM, Steven D'Aprano<steve@pearwood.info> wrote:

Your proposal certainly would lead to ambiguity in reading: _ = myfunc if _:_(_:_, ...) The "if _:_" means: if '_' evaluates to boolean true, call it The second _:_ uses your new lambda construct. Could a compiler parse it? Probably. Can a human understand it? Maybe, with difficulty, but it would surely lead to hard-to-find errors. On Sun, Aug 9, 2009 at 3:29 AM, ilya <ilya.nikokoshev@gmail.com> wrote:
-- Gerald Britton

On 9 Aug 2009, at 13:03 , Gerald Britton wrote:
And from the point of view of someone who'd really like a "better lambda", the "implicit lambda" idea is pretty much worthless. As others have said, it saves a few keystrokes and that's pretty much it. If work is done towards a better/more useable lambda, it should at least encompass full-blown anonymous expressions, not limit itself to the current restricted lambda.

I'd like to use this syntax only in situations of PEP 312, that is, where a colon is prohibited by current grammar. In those situations, writing _: is also prohibited by current grammar so it will be parsed unambiguously. The examples you quoted will not change under my idea, but ``x = (_:_*2)`` would be possible as an alternative. Note that I would be against being able to use ``x = _:_*2``. I think it's better to require either lambda keyword or parentheses for the RHS of the assignment as colon has a well-defined meaning as starting an indented block unless it's inside some brackets. On Fri, Aug 7, 2009 at 4:58 PM, Gerald Britton<gerald.britton@gmail.com> wrote:

On 7 Aug 2009, at 15:08 , ilya wrote:
It's not much of a gain though, some kind of currying for operators might be a more general idea for those cases. Or simply a better lambda syntax (Haskell has a pretty cool one for what it's worth, but it might conflict with the EOL escape thing), but as far as I know previous discussions on the subject have either failed to come up with a viable syntax or failed to get the approval of the community or BDFL.

ilya <ilya.nikokoshev@gmail.com> writes:
I was thinking about a good syntax for implicit lambdas for a while
Why were you thinking of this, and why is it important enough to override “explicit is better than implicit”?
and today I had this idea: make ``_:`` a shortcut for ``lambda _=None:``
-1. The name ‘_’ already sees a lot of use as an identifier. It is in common use as a conventional shortcut to the ‘gettext.gettext’ function. It is also commonly used as a name to bind to a value that is returned from some process but not actually needed. Overloading existing conventions of that valid identifier with this special construct is too much, in my view.
Even though ``:`` could theoretically denote implicit lambda, it's too easy to miss it. The combination ``_:`` is much easier to notice.
I disagree; it is too easy to miss. -- \ “Last year I went fishing with Salvador Dali. He was using a | `\ dotted line. He caught every other fish.” —Steven Wright | _o__) | Ben Finney

My suggestion for a lightweight lambda syntax is args -> expr Examples: map(x -> x + 5, something) d = defauldict(->[]) -- Greg

I notice you said "args" not "arg". How would you parse foo(x, y -> x + y)? Even if the compiler can parse it, how about the human reading the code? If lambda wasn't already there, I could see using (args) -> expr syntax but I think there shouldn't be two ways to do something so simple. If you really want a shorter syntax, the obvious choice is foo(λx, y: x + y). --- Bruce On Fri, Aug 7, 2009 at 5:49 PM, Greg Ewing <greg.ewing@canterbury.ac.nz>wrote:

08-08-2009 Greg Ewing <greg.ewing@canterbury.ac.nz> wrote:
-1 The idea would be nice, but "->" has already another meaning (in a different context -- function annotations -- but it's not a good idea to use the same "operator" for two completely different things, both connected with functions). *j

On Fri, 7 Aug 2009 10:46:40 pm ilya wrote:
[...]
Why would you want to get rid of the lambda keyword? What's the benefit? Is this about saving twelve keystrokes? lambda _=None: versus _: Just how often do you want, or need, to write such a lambda? It seems to me that not only is it a special case you want to break the rules for, which goes against the Zen, but it's an incredibly rare special case. _ as an identifier already has three conventional meanings: (1) In the interactive interpreter, _ is the value of the last expression typed. (2) It is commonly used to mean "I don't care about this value", e.g. t = ("Fred Smith", "123 Fourth Street", "New York", "dog") name, _, _, pet = t (3) It is also often used in internationalization. You want to give it the extra meaning "a default parameter name for lambda when I can't be bothered typing even a single letter name". Because _ is already a valid identifier, this will break code that does this: while _: process() _ = function() if _: print "something" Not the best choice of names, but somebody, somewhere, is doing that, and your suggestion will break their code. Looking at the three examples you gave: map( _: _ + 5, some_list) register_callback( _: True) def apply_transform(..., transform = _:_, ... ): In the first case, I wouldn't use the short-cut form even if it were available. I'd write a lambda that used a more meaningful name. In this case, I'm expecting an int, so I would use n, or a float, so I'd use x. I'd also avoid setting the pointless default: map(lambda x: x+5, some_list) vs map(_: _+5, some_list) Since your suggestion doesn't do precisely what I want, the only reason I would have for using your construct is to save seven keystrokes. Encouraging laziness on the behalf of the programmer is not a good reason for special-casing rare cases. Second case: register_callback( _: True) I assume you're implying that the callback function must take a single argument. In this example, using _ as the parameter name to the lambda makes sense, because it is a "don't care" argument. But if the callback function is documented as always being given a single argument, I would want to know if it was being called without any arguments, so the default value of None is inappropriate and I would avoid using it. Third case: def apply_transform(..., transform = _:_, ... ): I don't think I'd write a function called apply_transform() which made the transformation function optional, let alone buried deep in the middle of a whole lot of extra parameters. (I presume that's what the "..."s are meant to imply.) But putting that aside, I see your intention: a default do-nothing function which appears in a very long parameter list. The problem is that instead of trying to shrink the default value so you can fit all the parameters on a single line, you should make such a complicated function signature more readable by spreading it out: def apply_transform( obj, start, end, # start (inc) and end (exc) positions to apply another_arg, # does something very important I'm sure x=0, y=1, z=2, # more very important arguments transform=( # default null transformation lambda obj=None: obj), frotz=False, # if true, frotz the hymangirator with spangule hymangirator=None, spangule=None, magic=12345, # this needs no documentation namespace={}, flibbertigibbet=None, _private_magic=[] # the caller shouldn't supply this ): (Even better is to avoid such complicated function signatures, but sometimes that's not an option.) So again I'd be very unlikely to use your suggested construct except out of simple can't-be-bothered-to-type-a-dozen-letters laziness. Pandering to that sort of laziness is probably not a good thing. Fundamentally, this suggestion doesn't add expressability to the language, or power. Laziness on it's own is not a good reason for special casing rare cases. If it was a very common case, then *perhaps* you would have an argument for special casing needless verbiage: conciseness (up to a point) is a virtue in a language. That's partly why we have lambdas in the first place, so we can write this: reduce(lambda a,b: (a+b)/2.0, somelist) instead of this: def average(a, b): return (a+b)/2.0 reduce(average, somelist) But this isn't a common case, it's a rare case, and the case you're hoping to replace is pretty concise already. -- Steven D'Aprano

Steven D'Aprano wrote:
Why would you want to get rid of the lambda keyword? What's the benefit?
Is this about saving twelve keystrokes?
It's about conciseness. The only time it makes sense to write a function in-line is when the body is extremely short -- but then it gets swamped by the lambda keyword itself. But I agree that the OP's particular solution is restricted to a case that's too special. My version is completely general -- it can express anything that the existing lambda can express. -- Greg

Thank you and everyone else for insightful posts detailing why my examples don't make a good argument for the syntax. Even though my original suggestion, similarly pep 312, wouldn't break any existing programs and would not lead to ambiguity in 'if _:', I rescind it. However, another reason for implicit lambdas is lazy evaluation. For example, in another thread people discuss "... except ... if/else" conditional statement --- one reason being control expressions evaluate lazily. A function call passing callables currently looks ugly and unreadable: lazy_cond(expr, lambda: expensive(5), lambda: factorial(10**5)) and here 6 keystrokes of 'lambda' word *do* matter. Therefore I hope my unsuccessful proposal will encourage people to find something that works. On Sat, Aug 8, 2009 at 4:21 AM, Steven D'Aprano<steve@pearwood.info> wrote:

Your proposal certainly would lead to ambiguity in reading: _ = myfunc if _:_(_:_, ...) The "if _:_" means: if '_' evaluates to boolean true, call it The second _:_ uses your new lambda construct. Could a compiler parse it? Probably. Can a human understand it? Maybe, with difficulty, but it would surely lead to hard-to-find errors. On Sun, Aug 9, 2009 at 3:29 AM, ilya <ilya.nikokoshev@gmail.com> wrote:
-- Gerald Britton

On 9 Aug 2009, at 13:03 , Gerald Britton wrote:
And from the point of view of someone who'd really like a "better lambda", the "implicit lambda" idea is pretty much worthless. As others have said, it saves a few keystrokes and that's pretty much it. If work is done towards a better/more useable lambda, it should at least encompass full-blown anonymous expressions, not limit itself to the current restricted lambda.
participants (9)
-
Ben Finney
-
Bruce Leban
-
Gerald Britton
-
Greg Ewing
-
ilya
-
Jan Kaliszewski
-
Masklinn
-
Paul Moore
-
Steven D'Aprano