Thoughts on lambda expressions

I'm new here, but I know that lambda expression syntax has probably been discussed to oblivion. I have searched previous posts without finding anything exactly like my idea so here it is: # instead of this hand = sorted(cards, key=lambda card: card.suit) # sort some iterable of cards by suit # do this hand = sorted(cards, key=(card.suit from card)) # sort some iterable of cards by suit # |<= you can stop reading here and still have a good sense of what the code does More generally, I think a superior syntax for lambda would be: (<expression> from <signature>) The reasons I believe that's a superior syntax are: a) In the vast majority of use cases for lambda expressions the call signature can be easily inferred (like in a key function), so moving it after the expression tends to be more readable. b) It doesn't use the esoteric name, 'lambda' which causes its own readability issues. c) It should be compatible with existing code: try: 1/0 except Exception as e: raise (ValueError() from e) # this is already a syntax error so implementing the proposal won't break working code # of this form. I'm not aware of any other uses of the 'from' keyword that would create # ambiguities I'm not sure if this should actually be implemented, but I wanted to share the idea anyway and get some feedback. In my opinion 'lambda' is one of the less elegant pieces of Python syntax not because it's restricted to a single expression, but because the name and syntax are both detrimental to readability.

My objections to this are twofold: 1) It looks a lot like a lot of other 'structures' in python. It looks very much like a generator expression or a tuple, so it isn't immediately obvious to me what you are intending (if this was allowed syntax of course.) 2) While it is nice to type that over `lambda :`, typing lambda is no great burden, and that is already just sugar for a regular def statement. I don't think there is much of a great need for even more terse ways of writing an anonymous function, especially ones with the restrictions that python currently places on them (no statements). It just doesn't make a lot of sense to change the syntax at this point. But I think you knew that. On 3/2/2016 15:01, Abe Dillon wrote:

I rarely find myself wondering if something is a function call or a tuple or a generator expression or just an expression within '()' to promote order of operations. I don't see why this use case would all of a sudden make visual parsing all that more difficult, especially when there are often obvious context hints leading up to a lambda expression: most_distant_word = max(words, key=(edit_distance(word, "hello") from word)) distant_words = filter((edit_distance(word, most_distant_word) < 5 from word ), words) shortest_distant_word = min(distant_words, key=(len(word.strip()) from word )) lambda statements tend to be most expressive when used in an expected context (like as the 'key' argument to the sorted function or as the first argument to the filter function. 2) While it is nice to type that over `lambda :`, typing lambda is no
Typing 'lambda' is not at all my concern, in fact `(x+1 from x)` takes the same number of keystrokes as `lambda x:x+1`. My complaint is in readability which is supposed to be Python's strong suit. To most people, 'lambda' is pretty much a nonsense word. It might as well be 'quaple'. Would you be ok with writing: sorted(words, key=quaple word: edit_distance(word, "hello")) or would you rather write: sorted(words, key=(edit_distance(word, "hello") from word)) Most Python constructs are elegantly readable: with lock: mutate_shared_data() if any(thing.is_metal for thing in pockets): alarm.sound() You can write code that doesn't look like a mess of obscure symbols and esoteric words *except* for lambda expressions.

On Thu, Mar 3, 2016 at 11:01 AM, Abe Dillon <abedillon@gmail.com> wrote:
There's a difference between nonsense and jargon, though. Words used in programming languages are most often borrowed from a parent language (in Python's case, that's usually either English or algebra), but they don't always retain their exact meanings. Simple words like "if" and "while" are very close to their originals, but "def" (aka "define") has a very broad meaning in English, and doesn't necessarily have to mean "create a function" as it does in Python. No matter what your background is, you'll need to learn at least some of the syntax. Most of us probably learned what + means in grade school; but in algebra, "ab" means "a multiplied by b", whereas Python (like most other programming languages) allows variables to have multiple letters in their names, and spells multiplication with an asterisk. If you have to learn that "quaple" or "lambda" means "anonymous function", is that really worse than learning that "<expression> from <name list>" means "anonymous function"? ChrisA

On Thu, Mar 3, 2016 at 12:14 AM Abe Dillon <abedillon@gmail.com> wrote:
I also use lambdas for the various key= functions (sorted, min, max). I tend to use comprehensions instead of lambdas in filter. Still, in the examples you wrote, I might try some alternatives... farthest = max(words, key=partial(edit_distance, target="hello")) distant_words = [w for w in words if edit_distance(w, farthest) < 5] shortest = min(len(word.strip()) for word in distant_words) Typing 'lambda' is not at all my concern, in fact `(x+1 from x)` takes the
The phrase ``from thing`` suggests that ``thing`` is a container, not an argument. While I agree that reducing jargon is a good goal, the replacement with ``from`` unfortunately introduces a different jargon rather than making it sound like natural language. As you say, ``quaple`` is nearly as effective as ``lambda`` except for the handful of people who already knew the jargon from other languages. Unfortunately, both ``quaple`` and ``lambda`` are better than your usage of ``from`` because of the cognitive dissonance. Perhaps a keyword such as ``using`` might be better. Besides, I'd rather write that sorted example with functools.partial: sorted(words, key=partial(edit_distance, target='hello')) I'm not saying I think lambdas are great, but so far I haven't seen a convincing example for this new usage of ``from``.

On Wednesday, March 2, 2016 at 8:00:00 PM UTC-6, Michael Selik wrote:
I'm not saying I think lambdas are great, but so far I haven't seen a convincing example for this new usage of ``from``
I think the case has been made that `with` would be a better keyword. `using` would be great if it didn't introduce a new keyword that could break existing programs.

I hit send before my thought was really complete. I don't know if that is a contrived example or not, but python also already provides a more efficient and readable way of pulling attributes off of an object (a very common misuse of lambda/anonymous functions). |operator.||attrgetter, and it's cousin operator.itemgetter for item access. So for your example code, there is already a cleaner way. I don't know if that is your main use case. If it is not, then perhaps a better example could be provided where this would prove superior? | On 3/2/2016 15:01, Abe Dillon wrote:

On 03/02/2016 12:01 PM, Abe Dillon wrote:
And what does it look like when you have more than one paramater in the signature and/or something beside simple attribute lookup? 'open': lambda s, cr, uid, rec, ctx: rec['state'] == 'draft', would instead be: 'open': rec['state'] == 'draft' from (s, cr, uid, rec, ctx), Ouch. That just went from bad to horrid.
b) It doesn't use the esoteric name, 'lambda' which causes its own readability issues.
On the contrary: 'lambda' lets you know immediately what you're dealing with. The syntax you are suggesting looks like: - a (wrong) generator - taking ... items? ... from some kind of container To be fair, it looked like an interesting syntax at first glance, but deeper investigation shows serious drawbacks. -- ~Ethan~

Hi, I would just like to add a side note on this: The library fn.py implements a class called _Callable, which gives a shorter notation for lambdas, using an underscore ( _ ), instead of declaring parameters (for example, map(_ + 1, range(10)) is the same as map(lambda n: n + 1, range(10)) ). In addition to the regular arithmetic operators, it supports the __getattr__ method. (for instance _.y is the same as lambda a: a.y) Therefore, you do not override the general syntax of Python (other than the fact that you cannot use the code for i, _ in some_iterable: # don’t use, at the end of the loop, fn._ has disappeared from the scope of the module do_something(i) ) Personally, I would propose the adoption of the _ in some standard library module (e.g., functools) rather than overriding the “from” syntax if the simplification of lambdas in a goal. (Personal I find the _ much more user-friendly) - Ed M

On Wed, Mar 2, 2016 at 3:02 PM, Ed Minnix <egregius313@gmail.com> wrote:
+1 for fn.py's underscore functionality. But underscore already has a purpose as a placeholder and in the repl so I think it's a poor choice. In Python 3, you can actually do: from fn import _ as λ print(sorted(cards, key=λ.suit)) But that is hard to type on most keyboards. What if we allowed question marks in identifiers and used ``?.suit`` ? Grant

On 2 March 2016 at 22:46, Ethan Furman <ethan@stoneleaf.us> wrote:
I actually find the second case more readable, because the expression comes first. Having said that, I don't particularly like the proposal, but it's not really on grounds of readability. Or, for that matter, because it looks like a generator. My problem with the proposal is mainly that trying to cram too much into one expression is nearly always a mistake in Python. The language isn't expression-based and long, over-complex expressions are hard to work with and reason about. Splitting things up into smaller named subexpressions, or using conditional statements and loops rather than conditional expressions and comprehensions, nearly always makes things more readable (unless, like me, you're really bad at naming and end up with bits called e1, e2, e3... :-)) So a "nicer syntax for lambda" isn't really that helpful - we have one already, it's called "def" :-) For background, I've been working recently with a library that focuses strongly on providing a language for building complex expressions. The functionality is really powerful, but oh, boy, it's a struggle to express my intention in a single expression. So the basic problem for me is that the proposal doesn't offer huge benefits, and it's solving a problem that people should probably try to avoid in the first place. Paul PS For the record, I dislike the lambda syntax intensely - the odd keyword, the fact that "lambda" is sometimes almost as long as than the expression I'm using, the use of the mid-line colon which is hard to spot, ... So in principle I'm inclined to support "improvement" proposals.

On 2016-03-02 15:03, Paul Moore wrote:
Hmm, can't think of a way to get rid of the colon without it looking like a generator, but perhaps we could tackle the other issues by letting "def" stand in for "lambda": lambda x: x.y def x: x.y It's shorter, not an esoteric word, and is analogous to a named function definition, reminiscent of javascript. The lack of name/parens separates it from the standard form. Doable, but of course its pretty late in the game to be changing lambda, perhaps in Python 4? -Mike

On Wed, Mar 02, 2016 at 07:09:44PM -0500, Ed Minnix wrote:
Out of curiosity, what ambiguities do you see being introduced? Right now, only def function_name(foo, bar, baz=None): pass and async def function_name(foo, bar, baz=None): pass are parseable, from what I can see. Of course, type hints as well. Based on that, I can not yet see ambiguities. Am I missing something? One thing I do see as being different, is that `def` takes statements, not an expression. So, one should write an extra `return` as in sorted(datalist, key=def x: return x[5]) (Not requiring `return` here would be very confusing if one were to re-use the keyword `def`.) On the other hand, then one might even do something like sock.send_data(data, on_error=def err: some statements handling err , on_complete=def: draw a kitten ) Which starts looking very javascript-ish to me, so maybe never mind. Not to mention that the placement of the comma is troublesome. And of course that now the indent **within** an expression also has meaning. Now I said javascript, I'm even considering adding extra parenthesis around the arguments, giving (using the simple sort, again): sorted(datalist, key=def (x): return x[5]) And adding some type hints sorted(datalist, key=def (x: List[Int]) -> Int: return x[5]) I myself have learned Haskell before learning Python, so to me the `lambda` is not esoteric, and I have not considered it as such. However, I can understand that it would be considered as such by people coming to Python from other languages such as * Javascript having `function (foo, bar) { statements }` * Java having `(foo, bar) -> expression` or `(foo, bar) -> { statements }`. * C# being basically the same as Java, except for using a `=>` instead of `->`. For Java and C# I only did a quick 2-minute research, but it seems that Java and C# provide anonymous functions, while providing shorthand for expressions. Regarding changing it, I would be wary of it if only the syntax changed, without adding any actual benefits. Using an existing keyword (such as `def`) has the advantage that the meaning of currently working code does not change.

On Thu, Mar 3, 2016 at 11:46 AM, Sjoerd Job Postmus <sjoerdjob@sjec.nl> wrote:
Someone will correct me if I'm wrong, but I'm pretty sure Python's grammar cannot handle statements inside expressions. Creating a "def" expression that has a suite inside it would mess with everyone's heads AND the parser, and I'm pretty sure that one won't fly. ChrisA

On Thu, Mar 03, 2016 at 12:20:41PM +1100, Chris Angelico wrote:
I would be very surprised if the current grammar would be able to handle it. After all, it (rightfully) can't handle an assignment inside an expression either---like `if x = foo():`. I'm uncertain as to whether or not the grammar would be (easily) tweakable to allow a `def` suite inside an expression. I'm not familiar enough with the grammar (yet). As for messing with everyone's heads, I'm not worried about that too much yet. I think the example I gave does not look too bad (it somewhat follows Javascript idioms, though, and is thus not Pythonic). Now that Python has gotten async functions, it might very well be used even more for callback based programming. To me, that reminds me of Javascript, where inline definition of callbacks is the norm, not the exception. I'm not claiming that Python idioms in this regard can (or should or will) change in that direction, however I see that Java, Javascript, Ruby, C# (and possibly other languages as well) offer inline definition of multi-statement callbacks. Anyhow, this is completely off-topic, as the topic is about changing the syntax of a simple lambda, not on enabling multi-statement inline function definitions. So, unless somebody gets enthuasiastic enough to fork the thread off, I'll let it rest.

On Thu, Mar 3, 2016 at 11:00 AM, Mike Miller <python-ideas@mgmiller.net> wrote:
(Wow, I suck with the misclick. Or maybe this is a Zen koan - one letter of response that represents a wealth of wisdom and insight. Or not.) Trouble with this is that there'd be two very similar-looking, but syntactically disparate, constructs: # Define a function called x that calls another function # with itself as a parameter, and discards the return # value, always returning None. def x(): y(x) # Define and then dispose of an anonymous function # which takes a parameter and would return the # result of calling y on that object. def x: y(x) One of them is a statement, the other an expression. I'm not sure if the parser could handle that or not, but a lot of humans will have trouble with it. The similarities between these constructs will mean that a typo could easily flip the interpretation to the other, resulting in a bizarre error message. Consider what happens when you miss off a parenthesis: def function1(name): print("Hello, %s!".format(name) def function2(name): print("Goodbye, %s!".format(name)) Currently, the presence of the keyword 'def' inside an expression (the not-yet-closed print call) is an immediate error. But if "def" can introduce an anonymous function, the reported error might be a complaint about parentheses, or it might be to do with having no operator between the string method call and the function; depending on the exact syntax being used, this could result in extremely confusing errors. Much simpler if statements and expressions have a bit more distinction. And yes, I'm aware of the ternary conditional operator; and I don't think it sets a good precedent here. Comprehensions and genexps at least require bracketing, although they can run into the same oddities: print(x # oops, missed close bracket for x in y: # hey, what's that colon doing there? But I think this example is a smidge contrived. ChrisA

On 3 March 2016 at 00:00, Mike Miller <python-ideas@mgmiller.net> wrote:
To reinstate the context: even though I dislike the lambda syntax, in general I *don't* want it "improved" - instead I want a move away from needing it. Things that help: 1. Encouraging the community to appreciate that throwaway named function definitions are an acceptable approach. 2. Specialised syntax or (possibly 3rd party) modules for handling the common cases - the fn.py module sounds like a good example for handling simple expressions. I think we should keep lambda syntax for the relatively few cases where it would remain the best option, but I don't think it needs to be changed - if nothing else the backward compatibility issues would be too great. Paul

On Wednesday, March 2, 2016 at 5:04:10 PM UTC-6, Paul Moore wrote:
Yes, that's why I said, "I'm not sure if this should actually be implemented". People talk a lot about the 'expressiveness' of lambda statements, but the situations where they're actually more expressive than obfuscating are very rare and usually involve some idiom that makes the signature definition all but vestigial. filter(lambda num: num > 3, nums) # all that boiler plate before the part we really care about: filter(num > 3, nums) This is a minor improvement suggestion with some insight I've gleaned on code readability (putting the meat before the potatoes often improves readability, as does using more common english words).

On 3 March 2016 at 00:37, Abe Dillon <abedillon@gmail.com> wrote:
Understood, and (IMO) you're right about the improved readability. I think the costs mean that it's not worth implementing (as you suspected) but it's still a good principle ro remember. I actually quite liked Perl's "trailing control flow" constructs for much the same reason (put the key thing first). Using Python-like syntax (because I can't remember Perl these days): x = default if x is None x = x + 1 while fn(x) < 100 The problem with these being Perl's usual problem - they add yet more ways of saying the same thing we can already do. Paul

On Wednesday, March 2, 2016 at 4:45:22 PM UTC-6, Ethan Furman wrote:
what does it look like when you have more than one paramater in the signature and/or something beside simple attribute lookup?
The signature follows the exact same rules as a lambda signature: (func(*args, *kwargs) + offset from func, *args, offset, **kwargs) # vs. lambda func, *args, offset, **kwargs: func(*args, **kwargs) + offset Those both look bad because the expressiveness of lambdas loses its charm when the signature gets long and complicated. 'open': lambda s, cr, uid, rec, ctx: rec['state'] == 'draft',
Not only did you get the syntax wrong, but the lambda version is also horrid which is exacerbated by the fact that it looks like your trying to give the function a name or otherwise store it which defeats whole purpose of a lambda. At that point just use 'def' and stop trying to use lambda where it is ill suited.
the idea is from the recipe metaphor for a function: def <recipe>(<ingredients>): ...instructions to cook ingredients vs. (<make_something> from <ingredients>) It's fair to quibble over the exact implementation (maybe use 'with' instead of 'from') but the main point of the syntax it to put the important bit (i.e.the expression) in front of the (usually) unimportant bit (i.e. the signature) and to swap out an esoteric word (lambda) with something that continues the readability emphasis of Python by using more common words.

On Wed, Mar 02, 2016 at 04:19:42PM -0800, Abe Dillon wrote:
So, I'm looking at my recipe book, and it first tells me which ingredients I need, before telling me how to make the thing I want. I also think your perception that the expression is more important than the signature does not in general hold. After all, one writes def foo(bar, baz): <recipe> instead of def: <recipe> as foo(bar, baz) Furthermore, regarding simple lambdas---as in lambda x: <expression with x> The extra reading of `lambda x` is not that problematic. However, when you have a lambda needing multiple parameters---as in lambda param1, param2, param3=default: <expression> I think the order of the parameters and such is even more important, because it is an easy thing to have in the wrong order. Just out of curiosity, I grepped over the lambdas I could find in my (3.4) standard library. Of the 123 lambdas I found, only 12 of them have more than 1 argument. In most of these 12 cases, the only reason for the many arguments is to capture the value of a variable inside a loop, to make sure it uses the relevant version of that variable (and/or faster lookop).

On Wednesday, March 2, 2016 at 7:10:37 PM UTC-6, Sjoerd Job Postmus wrote:
So, I'm looking at my recipe book, and it first tells me which ingredients I need, before telling me how to make the thing I want.
Recipes are full of steps that could refer to other recipes but offer a more expressive form: cream the butter and sugar together # make cream from butter and sugar caramelize the sugar # make caramel from sugar Trying to apply the whole recipe metaphor to lambda expressions misses the point. Lambda expressions are expressive when their short and surrounded by context (like being the first argument to the 'map' function). They aren't comparable to a stand-alone recipe. It is possible to write arbitrary length programs in a lambda expression but that's not what they're meant for and it usually makes code more obfuscated than expressive.
Yes, that's because function definitions are different than lambda expressions and have a different use case. I'm not proposing that function definitions should follow the reverse syntax. Defined functions are usually abstracted away from any particular context while lambdas only make sense in very specific contexts.
It isn't *that* problematic, but it is noise. It could be better. That's what I'm proposing.
Again, the use cases for lambdas with complex signatures are very rare. Your own investigation confirmed this:

Note: Whatever fancy stuff you are doing to your messages is totally messing up trying to reply to you. On 03/02/2016 04:19 PM, Abe Dillon wrote:
Not only did you get the syntax wrong,
Ah, I see that I did. Oops.
If I was giving it a name I would use `def`. I am storing it, and that is a very common use of lambdas (to be fair, I stole one line from a multi-line dictionary definition).
At that point just use 'def' and stop trying to use lambda where it is ill suited.
This is exactly where lambda is suited.
Huh. Well, it looks good like that, but the actual examples were quite jarring to me.
Yeah, it would be better with `with`. But, really, I don't see it happening -- the whole anonymous function thing is not encouraged, so making it easier is not a goal. I wonder if MacroPy[1] would let you try it out? -- ~Ethan~ [1] https://pypi.python.org/pypi/MacroPy

On Wednesday, March 2, 2016 at 7:25:24 PM UTC-6, Ethan Furman wrote:
You're right. I'm sorry for getting uppity. I was thinking of the problems that arise when you try to store generators (not lambdas *brain fart*) instead of using them in situ. Whenever I've tried to store generators, it has lead to pain and suffering because they are ephemeral creatures. Lambdas, obviously are not.

On 02.03.2016 21:01, Abe Dillon wrote:
Why not this ? import operator hand = sorted(cards, key=operator.attrgetter('suit')) # For the curious: # https://docs.python.org/3.5/library/operator.html#operator.attrgetter -- Marc-Andre Lemburg eGenix.com Professional Python Services directly from the Experts (#1, Mar 03 2016)
2016-02-19: Released eGenix PyRun 2.1.2 ... http://egenix.com/go88 ::: We implement business ideas - efficiently in both time and costs ::: eGenix.com Software, Skills and Services GmbH Pastor-Loeh-Str.48 D-40764 Langenfeld, Germany. CEO Dipl.-Math. Marc-Andre Lemburg Registered at Amtsgericht Duesseldorf: HRB 46611 http://www.egenix.com/company/contact/ http://www.malemburg.com/

On 3 March 2016 at 06:01, Abe Dillon <abedillon@gmail.com> wrote:
This observation isn't necessarily accurate, as many uses of lambdas regularly rely on lexical scoping to look up some values (hence why the late binding behaviour of such lookups is frequently cited as a problem).
b) It doesn't use the esoteric name, 'lambda' which causes its own readability issues.
Given the readability issues caused by overuse of lambda, there's a school of thought that sees "I like lambda functions, but don't like the lambda keyword, so I avoid using lambda expressions in Python" as a desirable characteristic of the status quo.
Right, the main downside from an "existing syntax" perspective is that it would be a 3rd use of "from" that's semantically unrelated to the existing uses (imports, exception chaining).
I'm personally not averse to adding new syntactic sugar for lambda expressions, but if we did do something like that, I'd advocate for just stealing Java's spelling (perhaps with the addition of mandatory parentheses, ala generator expressions): https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html#s... The rationale for that would be: 1. "(params -> expr)" is easier on the eyes than "lambda params: expr" 2. "->" is already used to separate function parameter definitions from the return type annotation 3. It makes moving back and forth between Java & Python easier 4. Swift uses '->' to separate the parameter type and return type declarations in closure expressions [1] 5. It's also similar to the C# lambda expression syntax (which uses "=>" rather than "->") [2] 6. JavaScript ES6 also has an "arrow function" construct similar to the C# lambda expression [3] While that may sound like an "argument from popularity" (and there are certainly aspects of that), my main rationale for advocating for consistency with other popular (or operating system vendor backed) languages with similar capabilities would be to *increase Python's value as a teaching language*: making semantically similar constructs look similar to the way they look elsewhere makes it easier for folks that start their text-based programming education with Python to later make the move to a different platform (if that's where their career and interests takes them), and "helps in preparation for other environments" is a positive characteristic in a world where developers are spoiled for choice when it comes to programming languages and runtimes. However, I'm not interested enough in the idea to propose it myself - I'm interested in the problem from an abstract language design perspective these days, not a "this actually bothers me personally" sense [4]. [1] https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift... [2] https://msdn.microsoft.com/en-AU/library/bb397687.aspx [3] https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions/Arr... [4] That wasn't always true, as can be seen if you search far enough back in the dev list archives :) Regards, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia

On 3/2/2016 10:48 PM, Nick Coghlan wrote:
Not bad. 7. It is similar to the pattern matching expressions used in ml and probably elsewhere. fac: 0 -> 1 n -> n * fac(n-1) Of course as a lambda substitute, only one (generic) pattern is allowed and no recursion (absent the use of combinators, but ignore that).
-- Terry Jan Reedy

One qualifier on that: to meet the deliberate LL(1) parsing constraint on the language grammar, the actual syntax would probably need to be "(def params -> expr)" Generator expressions and comprehensions don't need an introductory token as the first child node is an ordinary expression, so the parser doesn't need any advance notice of the larger construct. That isn't the case with a parameter list - those have special parsing rules to allow things like default arguments, *args, and **kwds. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia

It still comes down to, for me, is ``def foo -> bar(foo)`` really any better than ``lambda foo: bar(foo)``? Are we gaining anything? Does it do anything that the lambda keyword does not? I have been (mostly) following this thread, and I cannot really see a real concrete problem with the lambda keyword and the colon. I don't really want to rain on parades here*, but unless something amazing can come out of new syntax (new functionality, because the readability gain in these proposals is debatable), I really don't think the syntax is going to change. Am I missing some great change in functionality here? If this discussion happened before lambda was added to the language, I think this would be a different story. * ok, I lied, I don't like this suggestion, so maybe I wanted to drizzle on it's parade. A spring shower at best. On 3/3/2016 02:54, Nick Coghlan wrote:

My objections to this are twofold: 1) It looks a lot like a lot of other 'structures' in python. It looks very much like a generator expression or a tuple, so it isn't immediately obvious to me what you are intending (if this was allowed syntax of course.) 2) While it is nice to type that over `lambda :`, typing lambda is no great burden, and that is already just sugar for a regular def statement. I don't think there is much of a great need for even more terse ways of writing an anonymous function, especially ones with the restrictions that python currently places on them (no statements). It just doesn't make a lot of sense to change the syntax at this point. But I think you knew that. On 3/2/2016 15:01, Abe Dillon wrote:

I rarely find myself wondering if something is a function call or a tuple or a generator expression or just an expression within '()' to promote order of operations. I don't see why this use case would all of a sudden make visual parsing all that more difficult, especially when there are often obvious context hints leading up to a lambda expression: most_distant_word = max(words, key=(edit_distance(word, "hello") from word)) distant_words = filter((edit_distance(word, most_distant_word) < 5 from word ), words) shortest_distant_word = min(distant_words, key=(len(word.strip()) from word )) lambda statements tend to be most expressive when used in an expected context (like as the 'key' argument to the sorted function or as the first argument to the filter function. 2) While it is nice to type that over `lambda :`, typing lambda is no
Typing 'lambda' is not at all my concern, in fact `(x+1 from x)` takes the same number of keystrokes as `lambda x:x+1`. My complaint is in readability which is supposed to be Python's strong suit. To most people, 'lambda' is pretty much a nonsense word. It might as well be 'quaple'. Would you be ok with writing: sorted(words, key=quaple word: edit_distance(word, "hello")) or would you rather write: sorted(words, key=(edit_distance(word, "hello") from word)) Most Python constructs are elegantly readable: with lock: mutate_shared_data() if any(thing.is_metal for thing in pockets): alarm.sound() You can write code that doesn't look like a mess of obscure symbols and esoteric words *except* for lambda expressions.

On Thu, Mar 3, 2016 at 11:01 AM, Abe Dillon <abedillon@gmail.com> wrote:
There's a difference between nonsense and jargon, though. Words used in programming languages are most often borrowed from a parent language (in Python's case, that's usually either English or algebra), but they don't always retain their exact meanings. Simple words like "if" and "while" are very close to their originals, but "def" (aka "define") has a very broad meaning in English, and doesn't necessarily have to mean "create a function" as it does in Python. No matter what your background is, you'll need to learn at least some of the syntax. Most of us probably learned what + means in grade school; but in algebra, "ab" means "a multiplied by b", whereas Python (like most other programming languages) allows variables to have multiple letters in their names, and spells multiplication with an asterisk. If you have to learn that "quaple" or "lambda" means "anonymous function", is that really worse than learning that "<expression> from <name list>" means "anonymous function"? ChrisA

On Thu, Mar 3, 2016 at 12:14 AM Abe Dillon <abedillon@gmail.com> wrote:
I also use lambdas for the various key= functions (sorted, min, max). I tend to use comprehensions instead of lambdas in filter. Still, in the examples you wrote, I might try some alternatives... farthest = max(words, key=partial(edit_distance, target="hello")) distant_words = [w for w in words if edit_distance(w, farthest) < 5] shortest = min(len(word.strip()) for word in distant_words) Typing 'lambda' is not at all my concern, in fact `(x+1 from x)` takes the
The phrase ``from thing`` suggests that ``thing`` is a container, not an argument. While I agree that reducing jargon is a good goal, the replacement with ``from`` unfortunately introduces a different jargon rather than making it sound like natural language. As you say, ``quaple`` is nearly as effective as ``lambda`` except for the handful of people who already knew the jargon from other languages. Unfortunately, both ``quaple`` and ``lambda`` are better than your usage of ``from`` because of the cognitive dissonance. Perhaps a keyword such as ``using`` might be better. Besides, I'd rather write that sorted example with functools.partial: sorted(words, key=partial(edit_distance, target='hello')) I'm not saying I think lambdas are great, but so far I haven't seen a convincing example for this new usage of ``from``.

On Wednesday, March 2, 2016 at 8:00:00 PM UTC-6, Michael Selik wrote:
I'm not saying I think lambdas are great, but so far I haven't seen a convincing example for this new usage of ``from``
I think the case has been made that `with` would be a better keyword. `using` would be great if it didn't introduce a new keyword that could break existing programs.

I hit send before my thought was really complete. I don't know if that is a contrived example or not, but python also already provides a more efficient and readable way of pulling attributes off of an object (a very common misuse of lambda/anonymous functions). |operator.||attrgetter, and it's cousin operator.itemgetter for item access. So for your example code, there is already a cleaner way. I don't know if that is your main use case. If it is not, then perhaps a better example could be provided where this would prove superior? | On 3/2/2016 15:01, Abe Dillon wrote:

On 03/02/2016 12:01 PM, Abe Dillon wrote:
And what does it look like when you have more than one paramater in the signature and/or something beside simple attribute lookup? 'open': lambda s, cr, uid, rec, ctx: rec['state'] == 'draft', would instead be: 'open': rec['state'] == 'draft' from (s, cr, uid, rec, ctx), Ouch. That just went from bad to horrid.
b) It doesn't use the esoteric name, 'lambda' which causes its own readability issues.
On the contrary: 'lambda' lets you know immediately what you're dealing with. The syntax you are suggesting looks like: - a (wrong) generator - taking ... items? ... from some kind of container To be fair, it looked like an interesting syntax at first glance, but deeper investigation shows serious drawbacks. -- ~Ethan~

Hi, I would just like to add a side note on this: The library fn.py implements a class called _Callable, which gives a shorter notation for lambdas, using an underscore ( _ ), instead of declaring parameters (for example, map(_ + 1, range(10)) is the same as map(lambda n: n + 1, range(10)) ). In addition to the regular arithmetic operators, it supports the __getattr__ method. (for instance _.y is the same as lambda a: a.y) Therefore, you do not override the general syntax of Python (other than the fact that you cannot use the code for i, _ in some_iterable: # don’t use, at the end of the loop, fn._ has disappeared from the scope of the module do_something(i) ) Personally, I would propose the adoption of the _ in some standard library module (e.g., functools) rather than overriding the “from” syntax if the simplification of lambdas in a goal. (Personal I find the _ much more user-friendly) - Ed M

On Wed, Mar 2, 2016 at 3:02 PM, Ed Minnix <egregius313@gmail.com> wrote:
+1 for fn.py's underscore functionality. But underscore already has a purpose as a placeholder and in the repl so I think it's a poor choice. In Python 3, you can actually do: from fn import _ as λ print(sorted(cards, key=λ.suit)) But that is hard to type on most keyboards. What if we allowed question marks in identifiers and used ``?.suit`` ? Grant

On 2 March 2016 at 22:46, Ethan Furman <ethan@stoneleaf.us> wrote:
I actually find the second case more readable, because the expression comes first. Having said that, I don't particularly like the proposal, but it's not really on grounds of readability. Or, for that matter, because it looks like a generator. My problem with the proposal is mainly that trying to cram too much into one expression is nearly always a mistake in Python. The language isn't expression-based and long, over-complex expressions are hard to work with and reason about. Splitting things up into smaller named subexpressions, or using conditional statements and loops rather than conditional expressions and comprehensions, nearly always makes things more readable (unless, like me, you're really bad at naming and end up with bits called e1, e2, e3... :-)) So a "nicer syntax for lambda" isn't really that helpful - we have one already, it's called "def" :-) For background, I've been working recently with a library that focuses strongly on providing a language for building complex expressions. The functionality is really powerful, but oh, boy, it's a struggle to express my intention in a single expression. So the basic problem for me is that the proposal doesn't offer huge benefits, and it's solving a problem that people should probably try to avoid in the first place. Paul PS For the record, I dislike the lambda syntax intensely - the odd keyword, the fact that "lambda" is sometimes almost as long as than the expression I'm using, the use of the mid-line colon which is hard to spot, ... So in principle I'm inclined to support "improvement" proposals.

On 2016-03-02 15:03, Paul Moore wrote:
Hmm, can't think of a way to get rid of the colon without it looking like a generator, but perhaps we could tackle the other issues by letting "def" stand in for "lambda": lambda x: x.y def x: x.y It's shorter, not an esoteric word, and is analogous to a named function definition, reminiscent of javascript. The lack of name/parens separates it from the standard form. Doable, but of course its pretty late in the game to be changing lambda, perhaps in Python 4? -Mike

On Wed, Mar 02, 2016 at 07:09:44PM -0500, Ed Minnix wrote:
Out of curiosity, what ambiguities do you see being introduced? Right now, only def function_name(foo, bar, baz=None): pass and async def function_name(foo, bar, baz=None): pass are parseable, from what I can see. Of course, type hints as well. Based on that, I can not yet see ambiguities. Am I missing something? One thing I do see as being different, is that `def` takes statements, not an expression. So, one should write an extra `return` as in sorted(datalist, key=def x: return x[5]) (Not requiring `return` here would be very confusing if one were to re-use the keyword `def`.) On the other hand, then one might even do something like sock.send_data(data, on_error=def err: some statements handling err , on_complete=def: draw a kitten ) Which starts looking very javascript-ish to me, so maybe never mind. Not to mention that the placement of the comma is troublesome. And of course that now the indent **within** an expression also has meaning. Now I said javascript, I'm even considering adding extra parenthesis around the arguments, giving (using the simple sort, again): sorted(datalist, key=def (x): return x[5]) And adding some type hints sorted(datalist, key=def (x: List[Int]) -> Int: return x[5]) I myself have learned Haskell before learning Python, so to me the `lambda` is not esoteric, and I have not considered it as such. However, I can understand that it would be considered as such by people coming to Python from other languages such as * Javascript having `function (foo, bar) { statements }` * Java having `(foo, bar) -> expression` or `(foo, bar) -> { statements }`. * C# being basically the same as Java, except for using a `=>` instead of `->`. For Java and C# I only did a quick 2-minute research, but it seems that Java and C# provide anonymous functions, while providing shorthand for expressions. Regarding changing it, I would be wary of it if only the syntax changed, without adding any actual benefits. Using an existing keyword (such as `def`) has the advantage that the meaning of currently working code does not change.

On Thu, Mar 3, 2016 at 11:46 AM, Sjoerd Job Postmus <sjoerdjob@sjec.nl> wrote:
Someone will correct me if I'm wrong, but I'm pretty sure Python's grammar cannot handle statements inside expressions. Creating a "def" expression that has a suite inside it would mess with everyone's heads AND the parser, and I'm pretty sure that one won't fly. ChrisA

On Thu, Mar 03, 2016 at 12:20:41PM +1100, Chris Angelico wrote:
I would be very surprised if the current grammar would be able to handle it. After all, it (rightfully) can't handle an assignment inside an expression either---like `if x = foo():`. I'm uncertain as to whether or not the grammar would be (easily) tweakable to allow a `def` suite inside an expression. I'm not familiar enough with the grammar (yet). As for messing with everyone's heads, I'm not worried about that too much yet. I think the example I gave does not look too bad (it somewhat follows Javascript idioms, though, and is thus not Pythonic). Now that Python has gotten async functions, it might very well be used even more for callback based programming. To me, that reminds me of Javascript, where inline definition of callbacks is the norm, not the exception. I'm not claiming that Python idioms in this regard can (or should or will) change in that direction, however I see that Java, Javascript, Ruby, C# (and possibly other languages as well) offer inline definition of multi-statement callbacks. Anyhow, this is completely off-topic, as the topic is about changing the syntax of a simple lambda, not on enabling multi-statement inline function definitions. So, unless somebody gets enthuasiastic enough to fork the thread off, I'll let it rest.

On Thu, Mar 3, 2016 at 11:00 AM, Mike Miller <python-ideas@mgmiller.net> wrote:
(Wow, I suck with the misclick. Or maybe this is a Zen koan - one letter of response that represents a wealth of wisdom and insight. Or not.) Trouble with this is that there'd be two very similar-looking, but syntactically disparate, constructs: # Define a function called x that calls another function # with itself as a parameter, and discards the return # value, always returning None. def x(): y(x) # Define and then dispose of an anonymous function # which takes a parameter and would return the # result of calling y on that object. def x: y(x) One of them is a statement, the other an expression. I'm not sure if the parser could handle that or not, but a lot of humans will have trouble with it. The similarities between these constructs will mean that a typo could easily flip the interpretation to the other, resulting in a bizarre error message. Consider what happens when you miss off a parenthesis: def function1(name): print("Hello, %s!".format(name) def function2(name): print("Goodbye, %s!".format(name)) Currently, the presence of the keyword 'def' inside an expression (the not-yet-closed print call) is an immediate error. But if "def" can introduce an anonymous function, the reported error might be a complaint about parentheses, or it might be to do with having no operator between the string method call and the function; depending on the exact syntax being used, this could result in extremely confusing errors. Much simpler if statements and expressions have a bit more distinction. And yes, I'm aware of the ternary conditional operator; and I don't think it sets a good precedent here. Comprehensions and genexps at least require bracketing, although they can run into the same oddities: print(x # oops, missed close bracket for x in y: # hey, what's that colon doing there? But I think this example is a smidge contrived. ChrisA

On 3 March 2016 at 00:00, Mike Miller <python-ideas@mgmiller.net> wrote:
To reinstate the context: even though I dislike the lambda syntax, in general I *don't* want it "improved" - instead I want a move away from needing it. Things that help: 1. Encouraging the community to appreciate that throwaway named function definitions are an acceptable approach. 2. Specialised syntax or (possibly 3rd party) modules for handling the common cases - the fn.py module sounds like a good example for handling simple expressions. I think we should keep lambda syntax for the relatively few cases where it would remain the best option, but I don't think it needs to be changed - if nothing else the backward compatibility issues would be too great. Paul

On Wednesday, March 2, 2016 at 5:04:10 PM UTC-6, Paul Moore wrote:
Yes, that's why I said, "I'm not sure if this should actually be implemented". People talk a lot about the 'expressiveness' of lambda statements, but the situations where they're actually more expressive than obfuscating are very rare and usually involve some idiom that makes the signature definition all but vestigial. filter(lambda num: num > 3, nums) # all that boiler plate before the part we really care about: filter(num > 3, nums) This is a minor improvement suggestion with some insight I've gleaned on code readability (putting the meat before the potatoes often improves readability, as does using more common english words).

On 3 March 2016 at 00:37, Abe Dillon <abedillon@gmail.com> wrote:
Understood, and (IMO) you're right about the improved readability. I think the costs mean that it's not worth implementing (as you suspected) but it's still a good principle ro remember. I actually quite liked Perl's "trailing control flow" constructs for much the same reason (put the key thing first). Using Python-like syntax (because I can't remember Perl these days): x = default if x is None x = x + 1 while fn(x) < 100 The problem with these being Perl's usual problem - they add yet more ways of saying the same thing we can already do. Paul

On Wednesday, March 2, 2016 at 4:45:22 PM UTC-6, Ethan Furman wrote:
what does it look like when you have more than one paramater in the signature and/or something beside simple attribute lookup?
The signature follows the exact same rules as a lambda signature: (func(*args, *kwargs) + offset from func, *args, offset, **kwargs) # vs. lambda func, *args, offset, **kwargs: func(*args, **kwargs) + offset Those both look bad because the expressiveness of lambdas loses its charm when the signature gets long and complicated. 'open': lambda s, cr, uid, rec, ctx: rec['state'] == 'draft',
Not only did you get the syntax wrong, but the lambda version is also horrid which is exacerbated by the fact that it looks like your trying to give the function a name or otherwise store it which defeats whole purpose of a lambda. At that point just use 'def' and stop trying to use lambda where it is ill suited.
the idea is from the recipe metaphor for a function: def <recipe>(<ingredients>): ...instructions to cook ingredients vs. (<make_something> from <ingredients>) It's fair to quibble over the exact implementation (maybe use 'with' instead of 'from') but the main point of the syntax it to put the important bit (i.e.the expression) in front of the (usually) unimportant bit (i.e. the signature) and to swap out an esoteric word (lambda) with something that continues the readability emphasis of Python by using more common words.

On Wed, Mar 02, 2016 at 04:19:42PM -0800, Abe Dillon wrote:
So, I'm looking at my recipe book, and it first tells me which ingredients I need, before telling me how to make the thing I want. I also think your perception that the expression is more important than the signature does not in general hold. After all, one writes def foo(bar, baz): <recipe> instead of def: <recipe> as foo(bar, baz) Furthermore, regarding simple lambdas---as in lambda x: <expression with x> The extra reading of `lambda x` is not that problematic. However, when you have a lambda needing multiple parameters---as in lambda param1, param2, param3=default: <expression> I think the order of the parameters and such is even more important, because it is an easy thing to have in the wrong order. Just out of curiosity, I grepped over the lambdas I could find in my (3.4) standard library. Of the 123 lambdas I found, only 12 of them have more than 1 argument. In most of these 12 cases, the only reason for the many arguments is to capture the value of a variable inside a loop, to make sure it uses the relevant version of that variable (and/or faster lookop).

On Wednesday, March 2, 2016 at 7:10:37 PM UTC-6, Sjoerd Job Postmus wrote:
So, I'm looking at my recipe book, and it first tells me which ingredients I need, before telling me how to make the thing I want.
Recipes are full of steps that could refer to other recipes but offer a more expressive form: cream the butter and sugar together # make cream from butter and sugar caramelize the sugar # make caramel from sugar Trying to apply the whole recipe metaphor to lambda expressions misses the point. Lambda expressions are expressive when their short and surrounded by context (like being the first argument to the 'map' function). They aren't comparable to a stand-alone recipe. It is possible to write arbitrary length programs in a lambda expression but that's not what they're meant for and it usually makes code more obfuscated than expressive.
Yes, that's because function definitions are different than lambda expressions and have a different use case. I'm not proposing that function definitions should follow the reverse syntax. Defined functions are usually abstracted away from any particular context while lambdas only make sense in very specific contexts.
It isn't *that* problematic, but it is noise. It could be better. That's what I'm proposing.
Again, the use cases for lambdas with complex signatures are very rare. Your own investigation confirmed this:

Note: Whatever fancy stuff you are doing to your messages is totally messing up trying to reply to you. On 03/02/2016 04:19 PM, Abe Dillon wrote:
Not only did you get the syntax wrong,
Ah, I see that I did. Oops.
If I was giving it a name I would use `def`. I am storing it, and that is a very common use of lambdas (to be fair, I stole one line from a multi-line dictionary definition).
At that point just use 'def' and stop trying to use lambda where it is ill suited.
This is exactly where lambda is suited.
Huh. Well, it looks good like that, but the actual examples were quite jarring to me.
Yeah, it would be better with `with`. But, really, I don't see it happening -- the whole anonymous function thing is not encouraged, so making it easier is not a goal. I wonder if MacroPy[1] would let you try it out? -- ~Ethan~ [1] https://pypi.python.org/pypi/MacroPy

On Wednesday, March 2, 2016 at 7:25:24 PM UTC-6, Ethan Furman wrote:
You're right. I'm sorry for getting uppity. I was thinking of the problems that arise when you try to store generators (not lambdas *brain fart*) instead of using them in situ. Whenever I've tried to store generators, it has lead to pain and suffering because they are ephemeral creatures. Lambdas, obviously are not.

On 02.03.2016 21:01, Abe Dillon wrote:
Why not this ? import operator hand = sorted(cards, key=operator.attrgetter('suit')) # For the curious: # https://docs.python.org/3.5/library/operator.html#operator.attrgetter -- Marc-Andre Lemburg eGenix.com Professional Python Services directly from the Experts (#1, Mar 03 2016)
2016-02-19: Released eGenix PyRun 2.1.2 ... http://egenix.com/go88 ::: We implement business ideas - efficiently in both time and costs ::: eGenix.com Software, Skills and Services GmbH Pastor-Loeh-Str.48 D-40764 Langenfeld, Germany. CEO Dipl.-Math. Marc-Andre Lemburg Registered at Amtsgericht Duesseldorf: HRB 46611 http://www.egenix.com/company/contact/ http://www.malemburg.com/

On 3 March 2016 at 06:01, Abe Dillon <abedillon@gmail.com> wrote:
This observation isn't necessarily accurate, as many uses of lambdas regularly rely on lexical scoping to look up some values (hence why the late binding behaviour of such lookups is frequently cited as a problem).
b) It doesn't use the esoteric name, 'lambda' which causes its own readability issues.
Given the readability issues caused by overuse of lambda, there's a school of thought that sees "I like lambda functions, but don't like the lambda keyword, so I avoid using lambda expressions in Python" as a desirable characteristic of the status quo.
Right, the main downside from an "existing syntax" perspective is that it would be a 3rd use of "from" that's semantically unrelated to the existing uses (imports, exception chaining).
I'm personally not averse to adding new syntactic sugar for lambda expressions, but if we did do something like that, I'd advocate for just stealing Java's spelling (perhaps with the addition of mandatory parentheses, ala generator expressions): https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html#s... The rationale for that would be: 1. "(params -> expr)" is easier on the eyes than "lambda params: expr" 2. "->" is already used to separate function parameter definitions from the return type annotation 3. It makes moving back and forth between Java & Python easier 4. Swift uses '->' to separate the parameter type and return type declarations in closure expressions [1] 5. It's also similar to the C# lambda expression syntax (which uses "=>" rather than "->") [2] 6. JavaScript ES6 also has an "arrow function" construct similar to the C# lambda expression [3] While that may sound like an "argument from popularity" (and there are certainly aspects of that), my main rationale for advocating for consistency with other popular (or operating system vendor backed) languages with similar capabilities would be to *increase Python's value as a teaching language*: making semantically similar constructs look similar to the way they look elsewhere makes it easier for folks that start their text-based programming education with Python to later make the move to a different platform (if that's where their career and interests takes them), and "helps in preparation for other environments" is a positive characteristic in a world where developers are spoiled for choice when it comes to programming languages and runtimes. However, I'm not interested enough in the idea to propose it myself - I'm interested in the problem from an abstract language design perspective these days, not a "this actually bothers me personally" sense [4]. [1] https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift... [2] https://msdn.microsoft.com/en-AU/library/bb397687.aspx [3] https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions/Arr... [4] That wasn't always true, as can be seen if you search far enough back in the dev list archives :) Regards, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia

On 3/2/2016 10:48 PM, Nick Coghlan wrote:
Not bad. 7. It is similar to the pattern matching expressions used in ml and probably elsewhere. fac: 0 -> 1 n -> n * fac(n-1) Of course as a lambda substitute, only one (generic) pattern is allowed and no recursion (absent the use of combinators, but ignore that).
-- Terry Jan Reedy

One qualifier on that: to meet the deliberate LL(1) parsing constraint on the language grammar, the actual syntax would probably need to be "(def params -> expr)" Generator expressions and comprehensions don't need an introductory token as the first child node is an ordinary expression, so the parser doesn't need any advance notice of the larger construct. That isn't the case with a parameter list - those have special parsing rules to allow things like default arguments, *args, and **kwds. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia

It still comes down to, for me, is ``def foo -> bar(foo)`` really any better than ``lambda foo: bar(foo)``? Are we gaining anything? Does it do anything that the lambda keyword does not? I have been (mostly) following this thread, and I cannot really see a real concrete problem with the lambda keyword and the colon. I don't really want to rain on parades here*, but unless something amazing can come out of new syntax (new functionality, because the readability gain in these proposals is debatable), I really don't think the syntax is going to change. Am I missing some great change in functionality here? If this discussion happened before lambda was added to the language, I think this would be a different story. * ok, I lied, I don't like this suggestion, so maybe I wanted to drizzle on it's parade. A spring shower at best. On 3/3/2016 02:54, Nick Coghlan wrote:
participants (13)
-
Abe Dillon
-
Alexander Walters
-
Chris Angelico
-
Ed Minnix
-
Ethan Furman
-
Grant Jenks
-
M.-A. Lemburg
-
Michael Selik
-
Mike Miller
-
Nick Coghlan
-
Paul Moore
-
Sjoerd Job Postmus
-
Terry Reedy