Alternate lambda syntax

Hi all, Lambdas can be defined as such: w = lambda: [12] x = lambda y: len(y) I'd like to propose the following: w = (): [12] x = (y): len(y) Or even another contraction for when there are no arguments: w =: [12] This would also be consistent with the other proposal on anonymous functions for defaults: https://mail.python.org/pipermail/python-list/2021-February/900795.html -- ∞

Hello, On Thu, 11 Feb 2021 12:24:55 +0100 "J. Pic" <jpic@yourlabs.org> wrote:
What will be the meaning of {(): [12]} ? Hint: it will be a dictionary of empty tuple mapping to a list, where do you see lambda here? Generally, if you have an idea like that, please go ahead and implement it with one of the existing macro engines for Python. That alone should give yourself more insight how viable it is. Here's tutorial to get you started: https://github.com/aroberge/ideas#usage -- Best regards, Paul mailto:pmiscml@gmail.com

Oh, I didn't think of it, thank you Paul. Inspiration from JavaScript was not a good idea. Instead, would like to propose to make the "def" keyword optional like in bash: foo(x): len(x) Would be equivalent to: foo = lambda x: len(x) Would that work? On Thu, Feb 11, 2021 at 12:24 PM J. Pic <jpic@yourlabs.org> wrote:
-- ∞ On Thu, Feb 11, 2021 at 12:48 PM Paul Sokolovsky <pmiscml@gmail.com> wrote:
-- ∞

I think you also need return, and double space pound space qa to pass linters: def foo(): return 1 # noqa Instead of foo = lambda: 1 And this proposal: foo(): 1 The benefit is just to get more out of the 80 characters when we want to define a short callback. I understand this is not a life changing proposal, but was wondering if it was "nice enough" to be worth proposing. Le jeu. 11 févr. 2021 à 15:43, Steven D'Aprano <steve@pearwood.info> a écrit :

On Thu, Feb 11, 2021, at 06:48, Paul Sokolovsky wrote:
This could be solved with parentheses, but I think it'd probably be better to use similar syntax to C#, Java, and Javascript instead, and use () -> [12] or () => 12... It's worth noting that all three of these are later additions to their respective languages, and they all have earlier, more difficult, ways of writing nested functions within expressions. Their designers saw the benefit of an easy lambda syntax, why don't we? It also may be worth looking at what it would take to allow asynchronous lambdas. Syntactically, while "any lambda containing await" is tempting, the lack of static typing means that we need a way to specify async lambdas that do not contain await. Javascript prefixes the argument list with async [i.e. "async () => ..." or "async onearg => ..."], as does C# even though it could in principle get away without doing so because of static typing.

On Thu, Feb 11, 2021 at 8:58 PM Random832 <random832@fastmail.com> wrote:
Agreed. I'd prefer the JavaScript solution, since -> already has a different meaning in Python return *type*. We could use -> to simplify typing.Callable, and => to simplify lambda.
Probably we were blinded by the endless search for for multi-line lambdas. It's not too late.
Makes sense. -- --Guido van Rossum (python.org/~guido) *Pronouns: he/him **(why is my pronoun here?)* <http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-c...>

Hello, On Thu, 11 Feb 2021 21:36:25 -0800 Guido van Rossum <guido@python.org> wrote:
Great to hear there's no desire to stray away from JavaScript just for the purpose of being different. I myself would never propose to take any bad ideas from JS, but in some areas, it now leads. And for wider context, it's the same idea with (informal so far) proposal to use "const" for defining *block-local* immutable variables, and "let" for *block-local* mutable vars. This isn't a bad choice on its own, but also matches what JavaScript ended up to have, and would help avoid confusion in wider programming language context. (And yes, that use of "let" does not match its use in pure-functional languages, but JS/Python are different beasts than pure-functional languages). [] -- Best regards, Paul mailto:pmiscml@gmail.com

Hello, On Fri, 12 Feb 2021 09:55:16 +0300 Paul Sokolovsky <pmiscml@gmail.com> wrote:
... And on the 2nd thought, that won't work. The reason it works in JS is that it doesn't have tuples. In Python, "(a, b) => (1, 2)" means "compare a tuple for greater-or-equal". But fear not, we can steal "lambda operator" from Haskell: \(a, b): (1, 2) Or... we can do nothing, and just promote macro usage in Python, because it's trivial to replace "lambda" with actual unicode lambda character (or anything else for that matter, for as long as "anything else" is not an empty string and not ambiguous with already existing constructs): https://aroberge.github.io/ideas/docs/html/lambda.html [] -- Best regards, Paul mailto:pmiscml@gmail.com

On 12/02/2021 07:32, Paul Sokolovsky wrote:
It takes a bit of mental processing to realise this isn't a valid comparison, and then more processing to understand what it does mean; it will definitely be a source of confusion for beginners. The fact that a very respected member of the community got it wrong at first sight suggests that many will do so. If we were going to do this - and I am still on the fence - I think we should avoid anything that reads like it could be confused as an operator.

On Fri, Feb 12, 2021, at 02:23, Paul Sokolovsky wrote:
Nope. greater-or-equal is >=, not =>. And Javascript may not have tuples, but it does have the comma operator.
But fear not, we can steal "lambda operator" from Haskell:
\(a, b): (1, 2)
That's another option [and might be easier to parse], but I think it's less readable.

On Thu, Feb 11, 2021 at 09:36:25PM -0800, Guido van Rossum wrote:
Please no! That will lead to constant confusion for people who can't remember which arrow operator to use. Is -> the return type symbol or the return value symbol? I forsee many Stackoverflow questions "What's the difference between -> and => ?" We've seen Paul mistake => for >= and he's not the only one. We already have chosen -> as the return type symbol in annotations, there is no ambiguity with also using it as the return value symbol. We could even allow both: (values:List[float], arg=0:int -> Type) -> expression There are plenty of popular and influential languages that use the single line arrow -> such as Maple, Haskell, Julia, CoffeeScript, Erlang and Groovy, to say nothing of numerous lesser known and obscure languages. -- Steve

Hello, On Sun, 14 Feb 2021 18:36:14 +1100 Steven D'Aprano <steve@pearwood.info> wrote:
Well, my mistake is based on the fact that I don't spend high-level neurons on remembering mundane low-level things, like order of characters if the "greater or equals" operator. Instead, low-level hands motor function neurons get it right when I type (most of the time ;-)). It's the same as I (and many other people I'm sure) don't remember phone numbers nowadays - why, if modern phones well remember them themselves, transfer from one instance to another, etc. Bottom line: after not too long practice, nobody would confuse ">=" and "=>", as they're different on their usage context (picked up subconsciously).
We already have chosen -> as the return type symbol in annotations, there is no ambiguity with also using it as the return value symbol.
You're mastermind to claim it like that. I for one wasn't sure there's no grammar-level ambiguity. Perhaps now I can say: if an arrow function appears in the type annotation position, then well, it's a type. That should work for the parser algorithm. But there another problem, on humans' side. For humans, it's very helpful when different concept look somewhat different. And it's very helpful to use different arrows for values vs types.
We could even allow both:
(values:List[float], arg=0:int -> Type) -> expression
I for one can't parse that (didn't have a morning coffee, but suspect there's a typo/thinko). Btw, I'm not sure about function values, but IMHO, type notation should always use parens for arguments, e.g. "(int) -> int".
The question is how many of those language have first-class type literals, and how many use the same notation for function literals and type literals. [] -- Best regards, Paul mailto:pmiscml@gmail.com

def func(x: int, y: int, f: (int, int) -> int) -> int: return f(x, y) print(func(1, 4, (x, y) -> x + y)) #Output: 5 I think we can still use the same syntax for both typing.Callable and lambda. It would act like Callable if it comes after the “:” in annotations or after the “->” in function return annotation. After assignment or using it directly as an argument, then it acts like lambda. func: (str, str) -> None = (text1, text2) -> print(text1 + text2) Same syntax, but communicates two different things. I don’t see any problem with this. func: (str, str) -> None = (text1, text2) => print(text1 + text2) is not bad either to be honest.

On Sun, Feb 14, 2021 at 11:23:59AM +0300, Paul Sokolovsky wrote:
That would be just great if code was written more than it is read. ("Doesn't matter that people reading the code confusion the symbols, nobody reads it; what matters is that my hands know what to type.") Or if we had a rule that only Python developers with a minimum of 10 years experience are allowed to use it. [...]
If I'm wrong, I'm sure somebody will point that out. I'm not frightened of making bold claims that turn out to be wrong: that just means I have learned something new. (Or something old that I forgot.) My reasoning is this: The arrow return annotation in def functions is only legal outside of the parameter list, and if it is there at all, it must immediately follow the parameter list. def func(params) -> ret_expression: So any time you see a def with a parameter list, inside the parameter list any arrows have to be the arrow function syntax. The first arrow immediately following the parameter list must be the return annotation, and any arrows following that must be part of ret_expression which could of course include more arrow functions. No matter how complicated the parameter list gets, the parser will never expect that return annotation arrow until the parameter list has completed and the closing parenthesis has been seen. Even if it is an unreadable mess to the human reader, to the interpreter it ought to be completely unambiguous: until you hit that closing parenthesis, you're still in the parameter list and so no arrow can be the function annotation arrow. Am I right so far? Things get a bit more complex if the arrow functions themselves can include annotations. Lambdas don't, so perhaps these won't either. But if they do, I have assumed a syntax like this: (a:T, b:T, c:T -> T) -> body where the return type annotation is inside the bracketed argument list. Each of those "T"s are, naturally, arbitrary expressions, so they could also include arrow functions. But the parser can always tell if it is looking inside the parameter list, and if so, if it is a default value, an annotation, the return annotation, or if it has reached the end of the parameter list and is now in the body. And of course, nothing in the arrow function (not the parameter annotations, default values, the return annotation, or the body) can contain a def with its `->` arrow. So I am: - very confident that there is no ambiguity between def function return annotations and arrow functions if they don't include annotations (as lambdas do not); - not so confident if they do support annotations; - but in that case, it ought to be resolvable. There you go: I have boldly laid my neck out on the chopping block. If I am wrong, I will be happy to be corrected.
But there another problem, on humans' side. For humans, it's very helpful when different concept look somewhat different.
And it is also very helpful to have similar concepts look similar. Return a value? The critical term here is **return**. Return type? The critical term here is also **return**.
And it's very helpful to use different arrows for values vs types.
Why is it helpful? Helpful to whom? I can see that it would be helpful to have different arrows if there were cases where the reader wasn't sure whether they were looking at an annotation or an arrow function, but I don't think that will ever be the case.
Yes, I swapped the order of the default value and the type annotation, it should read: (values:List[float], arg:int=0 -> Type) -> expression Sorry for the confusion. In case anyone is still having trouble parsing that: # lambda version lambda values, arg=0: expression # becomes arrow function (values, arg=0) -> expression # add parameter annotations (values:List[float], arg:int=0) -> expression # and the return type of the function body (expression) (values:List[float], arg:int=0 -> T) -> expression
What is this type notation you are talking about, and how is it relevant to Python and this proposal?
I don't think that question either makes sense or is important. We are not limited to "type literals", whatever that means to you. (To me, that would mean built-in reserved words for types, like `integer`, `real`, `boolean` in Pascal.) Types can be expressions, like `List[object]` or `Union[Spam, Eggs]`. -- Steve

Be bold, they say... On Mon, Feb 15, 2021 at 02:13:38AM +1100, Steven D'Aprano wrote:
Okay, there is an ambiguity, if arrow function syntax includes annotations with the syntax I suggested. I had: (values:List[float], arg:int=0 -> Type) -> expression Using that syntax, there is an ambiguous case: (arg=(a, b) -> T) -> expression That could mean: * Default value of arg is the arrow function `(a, b) -> T`; * Or the default value of arg is the tuple `(a, b)`, and the arrow function has the return type T. This may suggest that, like lambda, we should just not allow annotations in arrow functions; or that we need a better way to include the return annotation. The third fix is to use `=>` for the arrow functions, but this has many down-sides, as previously discussed. Anyway, the rest of my claim still stands (I think): if arrow functions don't include annotations there is no ambiguity between function annotations and arrow functions. -- Steve

Hello, On Thu, 11 Feb 2021 23:57:16 -0500 Random832 <random832@fastmail.com> wrote: []
No, it can't be - parentheses are optional, and without them, "(): [12]" and "{(): [12]}" would mean wildly different things. And any programming language should aim to minimize and avoid such cases. It's a similar concern which was raised for PEP642 (pattern matching alternatives), where syntax looking related to sets, was suddenly repurposed to mean dicts instead. Such cases are highly confusing. [] -- Best regards, Paul mailto:pmiscml@gmail.com

On 2021-02-11 03:24, J. Pic wrote:
I don't see any need for this. It's even more cryptic than "lambda" because at least lambda is a word you can look up. This is just inscrutable punctuation. Using different punctuation like "=>" doesn't help. The only thing that would be better than lambda is a less confusing keyword. So like "func x: x+2" would be better than "lambda x: x+2". That probably won't happen because no one wants to add new keywords. But adding new non-keyword ways to do this isn't worth it just to save a few keystrokes. -- Brendan Barnwell "Do not follow where the path may lead. Go, instead, where there is no path, and leave a trail." --author unknown

I actually like the “(x, y=7) => x + y” and “async (x, y) => asyncio.sleep(x + y)” for both normal and async anonymous functions respectfully. I have natural aversion to the word lambda for some reason. The normal anon function has “return” implicitly, and the async anon function has “return” implicitly as well. Usage: f1 = (x, y=7) => x + y f1(3) outputs 10 f2 = async (x, y) => asyncio.sleep(x + y) async def main(): coro = f2(3, 7) await coro return “waited 10 seconds” result = asyncio.run(main()) print(result) # outputs “waited 10 seconds” Also, this is very close to what I brought back to discussion some time ago, which is typing.Callable.. instead of =>, we do -> for it. Correct me guys if you find any mistakes in the above. Python with those new proposal and Match Pattern will be so much more elegant. Abdulla Sent from my iPhone

On Fri, 12 Feb 2021 at 09:26, Abdulla Al Kathiri <alkathiri.abdulla@gmail.com> wrote:
I actually like the “(x, y=7) => x + y” and “async (x, y) => asyncio.sleep(x + y)” for both normal and async anonymous functions respectfully.
I think it's a reasonable syntax, although it could be over-used. That's not an issue with the syntax, though - *anything* can be over-used :-) Experience with similar syntax in other languages suggests this would be useful.
I have natural aversion to the word lambda for some reason.
It does seem to cause people (including me!) a lot more problems than one would expect, on the face of it. Maybe because it's not a common term outside of computer science? But the endless debates over alternative keywords have never come up with anything else that people can agree on.
I'm not sure what the use cases would be for an async lambda - the key is that it's not named, so the above isn't a good example as it's just as easy to write async def f2: return asyncio.sleep(x+y) (Excuse any errors here, I'm not that familiar with asyncio). If there are good use cases, I think it makes sense to include async lambda in any proposal. I'm not saying that it isn't useful, just that it doesn't have all the history that (non-async) lambda does, so the argument in favour of async lambda isn't as strong. Use cases are key - adding it "just because we can" would just make the proposal more controversial, and then the whole thing could collapse over something secondary. Ultimately, this would need someone to write a PEP. Paul

I am not that familiar with asyncio either. I only wrote a few utility scripts that runs concurrent subprocesses mixed with some blocking functions running in concurrent.ProcessPoolExecutor pool (using asyncio.run_in_executor). That is all what I did with regard asyncio. Your function f2 and my function f2 could be actually normal functions. f2 = (x, y) => asyncio.sleep(x + y). f2(3, 7) will just return a coroutine that can be awaited on just fine. To be honest, i don’t even know what the purpose would be with async lambda unless someone with more experience can give us a use case. My guess is that it may be useful to use it as an argument to another async function. Since we can write shortened normal functions (lambda), shortened generator function (lambda with generator expression), people might ask why Python doesn’t have shortened async function? But maybe that is not a good question to begin with? Lambda reminds me of the half life time of isotopes. The other day, I was struggling to teach this to my cousin in elementary school. I just told him to imagine it like def _(args): return something. Assign it to a variable and that variable replaces the underscore. He got it but he found it weird. Sent from my iPhone

Fair enough. Whoever writes a PEP for this will need to do the relevant research and present the arguments in detail. But until someone's ready to write that PEP, we can continue discussing on the assumption that if someone finds the async version useful, they'll speak up. Paul On Fri, 12 Feb 2021 at 11:24, Abdulla Al Kathiri <alkathiri.abdulla@gmail.com> wrote:

On Fri, Feb 12, 2021 at 7:57 PM Brendan Barnwell <brenbarn@brenbarn.net> wrote:
sigh. That argument again? I just asked Google about "javascript =>" and got a bunch of perfectly good results. Some said "arrow function", others have "=>" in the title: https://stackoverflow.com/questions/24900875/whats-the-meaning-of-an-arrow-f... Yes, you CAN search for punctuation. Please can this argument die? ChrisA

On 2021-02-12 03:18, Chris Angelico wrote:
Okay, fine, drop that argument. It doesn't matter. The point is that we currently have a way to write anonymous functions and this proposal adds NO BENEFIT WHATSOEVER except that instead of typing "lambda" you type two parentheses, thus saving you a grand total of two keystrokes (you need to hit shift to get the parentheses, but not to type "lambda") to get something that doesn't look any less cryptic. Also the fact that JavaScript does something is evidence that it's probably not a good idea. :-) I just don't understand what makes people think that "(a, b): a+b" or "(a, b) => a+b" or any of these other variants has any advantage at all over "lambda a, b: a+b". Yes, "lambda" is cryptic and mysterious, but so are all these alternatives. They don't solve any problems or allow anything that wasn't already possible and they would just clutter up the language. -- Brendan Barnwell "Do not follow where the path may lead. Go, instead, where there is no path, and leave a trail." --author unknown

On Fri, Feb 12, 2021 at 1:00 AM Brendan Barnwell <brenbarn@brenbarn.net> wrote:
Is this really what this is all about? removing that word? I do think that adding a parens around the parameters would make it a bit more clear, but it currently illegal: In [18]: lambda(x, y): x + y File "<ipython-input-18-0f5b071bce98>", line 1 lambda(x, y): x + y ^ SyntaxError: invalid syntax
So like "func x: x+2" would be better than "lambda x: x+2". That probably won't happen because no one wants to add new keywords.
There seems to be a frequent objection to the word "lambda" -- personally, I found it cryptic, but it's not hard to remember, and it IS easy to look up. But if you don't like that word, why not "def"? Every place I've tried to use "def" where "lambda" is legal, it's a syntax error. So we could use the same word. Would that be less confusing? My thought is yes it would , IF we were stating from scratch -- but this would be a lot of churn in code and documentation for very little gain. -Chris B
-- Christopher Barker, PhD (Chris) Python Language Consulting - Teaching - Scientific Software Development - Desktop GUI and Web Development - wxPython, numpy, scipy, Cython

On Sun, Feb 14, 2021 at 9:33 AM Christopher Barker <pythonchb@gmail.com> wrote:
It is currently illegal, but in previous Pythons, it was legal, with different semantics. Python 2.7.16 (default, Oct 10 2019, 22:02:15) [GCC 8.3.0] on linux2 Type "help", "copyright", "credits" or "license" for more information.
ChrisA

Hello, On Sat, 13 Feb 2021 14:33:43 -0800 Christopher Barker <pythonchb@gmail.com> wrote:
There seems to be a bit too many posts downputting the "lambda" keyword, and nobody went for its defense, so let me do that. The "lambda" is perhaps the greatest thing in Python after... after... well, maybe it's the single greatest thing in Python. As someone coming to Python from LISP (many years ago), I really appreciate it, and always considered Python to be "a LISP for real world". So, it's of great utility to people familiar with functional programming, but even of more utility to novices who are not yet - thanks to it, by looking it up, they can get acquainted with the wonderful world of functional programming and history of programming languages. Lambda is a sacred keyword, please don't touch! -- Best regards, Paul mailto:pmiscml@gmail.com

"lambda" is unnecessarily obscure. Beginner: "why is it called lambda?" Teacher: "Don't worry about it, just use it to define a function" I'm not taking a side on whether to change Python, but let's please not lose sight of just how opaque the word "lambda" is. People who know the background of lambda can easily understand using a different word. People who don't know the background are presented with a "magic word" with no meaning. That's not good UI. --Ned. On 2/14/21 11:39 AM, Paul Sokolovsky wrote:

On Tue, 16 Feb 2021 at 16:40, Ned Batchelder <ned@nedbatchelder.com> wrote:
Agreed. When lambda was introduced, "anonymous functions" were not as common in programming, and the most obvious example of their usage was in lisp, where "lambda" was the accepted term. Since then, lisp has not gained much additional popularity, but anonymous functions have appeared in a number of mainstream languages. The syntax is typically some form of "a, b -> a+b" style, and *never* uses the term "lambda". So someone coming to Python with any familiarity with other languages will now find Python's form atypical and obscure. People coming with no experience of other languages will need to have a history lesson to understand why the term is "lambda" rather than "something more obvious". People can, and will, learn Python's syntax. This isn't a major disaster. But if this were a new feature, we'd not be having this discussion, and "lambda" wouldn't even be a consideration. I'm also not taking a side on whether a change is worth the disruption. Personally, I prefer the arrow syntax, but we're not making a decision in a vacuum here. Someone has to make a case (probably in a PEP) if this is going to change, and the trade-offs should be clarified there. Paul

On Tue, Feb 16, 2021 at 11:38:33AM -0500, Ned Batchelder wrote:
That's a bad answer. A better answer that is more appropriate for nearly everyone is "It's Greek letter, like pi that you may remember from maths class. In some technical computer science, the Greek L, lambda, is used as the symbol for functions." Two sentences, a few seconds to say. At this point the student almost certainly will be either satisfied with the answer, and have learned something new, or will be satisfied with the fact that there is an answer, and promptly forget it because they didn't really care, they just want to know that there is a reason. And for that perhaps one in fifty who go on to ask "Why lambda?", the answer is "They had to choose some letter, and lambda was the one they picked." I don't understand people who are unwilling to explain things. It makes me sad.
You know the approximately 7.4 billion people in the world who aren't native English speakers? And the approximately 5 billion people who speak no English at all? They just said "Welcome to our world!" Honestly, I think this argument about lambda being a magic word is both privileged and silly. Its no more "magic" than tuple, deque, iterator, coroutine, ordinal, modulus, etc, not to mention those ordinary English words with specialised jargon meanings like float, tab, zip, thread, key, promise, trampoline, tree, hash etc. It's just a word. Every single word that we know had "no meaning" to us at some point. None of us were born knowing what "raise" or "hex" means. There is a *ton* of jargon to learn on the way to becoming a decent programmer, I don't know why lambda is singled out for so much hate. Personally I had much more difficulty learning "tuple", or "turple" as I insisted on spelling it for about the first five years. And I still don't know where the word comes from in the first place. Given that it is used in maths, probably Latin, Greek or Arabic. -- Steve

On 16.02.2021 23:13, Greg Ewing wrote:
The Python notation for anonymous function is almost a direct reference to the original notation for such functions in lambda calculus: λx.x+1 ... lambda x: x+1 I think that's an excellent hint for students to look up on this great piece of mathematical logic: https://en.wikipedia.org/wiki/Lambda_calculus and learn something about the foundations of computer science. Why the Greek letter lambda ? Who knows -- mathematicians love Greek letters, logic is λογική in Greek, ... https://en.wikipedia.org/wiki/Lambda_calculus#Origin_of_the_lambda_symbol And, of course, if you don't like anonymous functions, you're always free to give your functions names in Python ;-) -- Marc-Andre Lemburg eGenix.com Professional Python Services directly from the Experts (#1, Feb 17 2021)
Python Projects, Coaching and Support ... https://www.egenix.com/ Python Product Development ... https://consulting.egenix.com/
::: 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 https://www.egenix.com/company/contact/ https://www.malemburg.com/

On Wed, Feb 17, 2021 at 11:13:08AM +1300, Greg Ewing wrote:
Not according to Alonzo Church, who at various times has stated that it was either more or less chosen at random, or that it was derived from Whitehead and Russell's x̂ (x-hat) via ∧x to λx to make it easier for the printers. Either way it wasn't a mistake, but a deliberate choice. It is really remarkable how much attention lambda gets. As far as I know, mathematicians don't ask why Hilbert chose epsilon for his epsilon calculus, and nobody ever asks where "byte" comes from. It is, apparently, a deliberate misspelling of bite, to avoid it being accidently changed to bit. But why *bite*? The first published use of "byte" apparently was in a 1956 IBM memo by Werner Buchholz: "[…] Most important, from the point of view of editing, will be the ability to handle any characters or digits, from 1 to 6 bits long. Figure 2 shows the Shift Matrix to be used to convert a 60-bit word, coming from Memory in parallel, into characters, or 'bytes' as we have called them, to be sent to the Adder serially." The memo already shows that Buchholz and IBM were thinking of multiple bits being a "word", so it's not clear why bytes. There's no ordinary sense that a collection of bits (as in "a bit of stuff") is considered "a bite". Language is fun. -- Steve

On 17/02/21 7:10 am, Steven D'Aprano wrote:
Actually, I think it is -- all those words build on a pre-existing meaning in some way, and in most cases you can trace the etymology back to something the person is most likely already familiar with. Lambda, on the other hand, is a completely fresh arbitrary choice. I agree that the technical meaning has to be taught in any case, though. -- Greg

Ned Batchelder writes:
"lambda" is unnecessarily obscure.
And it should be. It's really only useful as an argument. There's no advantage to foo = (x) -> 1 vs. def foo(x): return 1 except a couple of characters. So what currently looks like some_list.sort(key=lambda e: e[3].priority) would then be some_list.sort(key=(e)->e[3].priority) which is shorter but not particularly more readable (and already has a familiar meaning in C-like languages). It seems to me that two changes to def might be considered: 1. In a one-line def of the form "def foo([arglist]): return EXPR", "return" may be omitted, and the function returns the value of EXPR (rather than None as currently). (As a multiline def, EXPR would be presumed to be evaluated for side effects, and 2. As an actual argument, a one-line def is interpreted not as a positional argument, but as a keyword argument, so that in some_list.sort(def key(e): e[3].priority) the name "key" is not optional, and must match a keyword argument. I suggest 1 for "ordinary" defs as well for consistency, but evidently we could also restrict that usage to "def as keyword argument", and maintain backwards compatibility. 2 could even be independent of 1: some_list.sort(def key(e): return e[3].priority) but that seems excessively verbose. Another possible use case would be in a for loop: for fun in [def fun(): return 1, def fun(): return 2, def fun(): return 3]: do_something_with(fun) where similarly the loop variable needs to match the def.
Beginner: "why is it called lambda?"
Teacher: "Don't worry about it, just use it to define a function"
It me. But it would go like this: Teacher [face lights up at the chance to talk math history]: "You see, ..." Students [in harmony]: "NOOOOOOOOooooooo.......... :-(" [collective sigh] Regards, Steve

On Tue, Feb 16, 2021, at 23:24, Stephen J. Turnbull wrote:
Let's not pretend the key argument being keyword-only isn't a wart. Surely this would be better if it could be some_list.sort(e->e[3].priority).
which is shorter but not particularly more readable (and already has a familiar meaning in C-like languages).
this side point is an argument in favor of using => instead. [and if => can be confused with >=, surely so can -> be confused with >-]
I would like something like this - it's worth noting that C# [and as someone helpfully pointed out, Dart] uses => for this case as well, and the argument about the syntax looking bad when a return type annotation is present is, I think, overblown - return type annotations are almost never needed for a function with a single return statement.

On 2/17/21 8:47 AM, Random832 wrote:
On Tue, Feb 16, 2021, at 23:24, Stephen J. Turnbull wrote:
No need to pretend, it isn't a wart. -1 on removing the lambda keyword. Just because excessive punctuation works for other languages does not mean it's a good fit for Python. -- ~Ethan~

On Wed, 17 Feb 2021 at 15:31, Ethan Furman <ethan@stoneleaf.us> wrote:
If someone comes with a "pythonic" way to lift restrictions on lambda, that could be something for debate, but so far this is just about uglifying it, and creating a new syntax matching exactly what exists today. Moreover I'd like to remind people so much worried about expressiveness in less and less characters that Lambda is much less needed in Python than in similar languages due to the existence of the comprehensions and generator expression constructs. The energy spent here could be focused instead on having an equivalent of comprehensions for "reduce", for example.

On Wed, 17 Feb 2021 at 18:15, Abdulla Al Kathiri < alkathiri.abdulla@gmail.com> wrote:
Well, for m eyes, the above is definetellly "perlonic" . it could be "j" before being Pyrhon. This is Pythonic: def f1(x, y): return x + y def f2(): return 0 def f3(x): return x ** 2 And it took me a while looking at our example to check it was not really fuction composition with default parameters, or what. I mentioned violation of 6 of the first 7 phrases in the famous "zen of Python" - most important of which can be reasonably agreed is the 7th: "Readability counts". If you don't want readability at all in exchange for typing a few keywords (which more and more automatic tools can auto-complete), I'd suggest going for the "forth" language. Abdulla

Hello, On Wed, 17 Feb 2021 18:43:09 -0300 "Joao S. O. Bueno" <jsbueno@python.org.br> wrote:
As said many times already, that's not Pythonic, because "->" is used in Python for return *type* annotation, and thus cannot be used as lambda synonym (without hampering understandability for machines and humans). To illustrate it, (x, y) -> x + y translates to: Callable[[x, y], x + y] while (x, y) => x + y translates to: lambda x, y: x + y Huge difference.
Well, for m eyes, the above is definetellly "perlonic" . it could be "j" before being Pyrhon.
That's unlikely, in Perl it would be something like $x+$y $) ql/x y/. As was said from the very beginning, "(x, y) => x + y" is "JavaScriptonic". For reference, JavaScript is the world's leading programming language, and now even turned out that it has some "good parts" (much later than originally supposed). So, people are looking how to "steal" those good parts. (Just the same as previously, JS "stole" generators from Python). -- Best regards, Paul mailto:pmiscml@gmail.com

I will be very happy if those versions of Callable and anonymous functions exist in Python right now. See how elegant that would look like.. def func(x: int, y: int, f: (int, int) -> int) -> int: return f(x, y) print(func(3, 4, (x, y) => x + y)) #Out: 7 Imagine your mouse is on :func: ‘func’ in VSC or PyCharm and see that you need the third parameter to be of type (int, int) -> int, you can immediately write an anonymous function that mirrors the structure of the annotation but instead of ->, you have =>. Straight forward.

On 2021-02-18 at 18:10:16 +0400, Abdulla Al Kathiri <alkathiri.abdulla@gmail.com> wrote:
Elegant? I realize that this is a contrived scenario, but even if the identifiers x, y, and f were meaningful (e.g., account_balance, socket_descriptor), the signal to noise ratio in that definition makes me cringe. And it only gets worse once I'm not dealing with ints.
If my IDE is that clever, then it can also type "lambda x, y: " for me in addition to showing me that signature. Aside: And then a thousand developers/engineers/maintainers, auditors, and testers (not to mention future me) have to read that anonymous function. Over and over. And over. Unless it's trivial, or simpler, use a def statement, give it a name and a doc string, test it, and reuse it. And if it's that trivial, then trading "lambda" for "->" (or "=>") doesn't matter.

2QdxY4RzWzUUiLuE@potatochowder.com writes:
I'm -1 on the Arrow proposal, but old Lisper that I am I do define functions like that. I would write it: def post_to_auditor( account_balance: PosIntPennies, socket_descriptor: Socket, validator: (PosIntPennies, Socket) -> Bool ) -> Bool: which I don't think is bad at all.[1] Is the S/N really so bad? (Aside from the fact that try as I could I couldn't think of even one reason for passing both account_balance and socket_descriptor to the same user-supplied function, an idea that made my ears ring). I think it's important in these things that we avoid taking toy examples and criticizing them for points that they weren't intended to make. It's also useful to use real code to avoid this kind of criticism. Most of the really strong arguments for syntax changes that I've seen take the stdlib, or some other large body of code (in this case I would bet Sympy would be a candidate) and show how the change improves its expressiveness. Footnotes: [1] Don't ask me about the docstring, I am a game theorist, not an accountant nor a network engineer.

def test(self, func: t.Callable[..., bool], *args, **kwargs) -> Predicate: """ Run a user-defined test function against the value. >>> def test_func(val): ... return val == 42 ... >>> var('f1').test(test_func) :param func: The function to call, passing the dict as the first argument :param args: :param kwargs: Additional arguments to pass to the test function """ return self._build_predicate( lambda lhs, value: func(lhs, *args, **kwargs), Operation.TEST, (self._path, func, args, freeze(kwargs)) ) Becomes .... def test(self, func: (...) -> bool, *args, **kwargs) -> Predicate: """ Run a user-defined test function against the value. >>> def test_func(val): ... return val == 42 ... >>> var('f1').test(test_func) :param func: The function to call, passing the dict as the first argument :param args: :param kwargs: Additional arguments to pass to the test function """ return self._build_predicate( (lhs, value) => func(lhs, *args, **kwargs), Operation.TEST, (self._path, func, args, freeze(kwargs)) ) Sent from my iPhone

Abdulla Al Kathiri writes: Condensing to the parts which are in question,
Yes, it's nicer, but I don't see a win big enough to be worth forcing people who read code to learn two syntaxes for lambda, and two syntaxes for Callable (one of which isn't even syntax). Also, "->" can't be just syntax, if I understand type annotations correctly. It would need to become an object constructor. Then the question would be "are there cases where 'Callable' is not what you want there?", i.e., you want a subclass of Callable. In that case you'd have to use the old syntax anyway. (I don't have an answer to that, but you would need one.) I don't make the rules, but to me if this is the best you can do, you would have to provide evidence that quite a lot of code would benefit from this. Steve

Hello, On Sat, 20 Feb 2021 00:23:13 +0900 "Stephen J. Turnbull" <turnbull.stephen.fw@u.tsukuba.ac.jp> wrote:
People won't learn "two syntaxes for Callable". People shun using Python's current type annotations due to their ugliness and "quick hack without thinking of UX" feel. Only after there will be "int | str" instead of "Union[int, str]", "(int, str) -> int" instead of "Callable[[int, str], int]", "int & const" instead of "Annotated[int, const]" - only then people will start learn and use them.
It depends on how "->" in that role will be implemented. It would be nice to not just hardcode it to "Callable[lhs, rhs]", but at the same time, I'd personally hope we'll avoid yet another dunder either.
There can't be subclass of Callable in the same way as there can't be: class my_foo(type(lambda:0)): pass
The difference between "(int, str) -> int" and "Callable[[int, str], int]" is the same as difference __str__ and __repr__. "Callable" syntax is effectively an internal representation of the type annotation information. And currently, the people have to write that verbose, unwieldy, ugly representation (which normally would be needed only for debugging purposes) manually. What we need is pleasant surface syntax for type annotations in Python. So no, __str__ vs __repr__ comparison doesn't do fairness to it. The difference is the same as between: --- def foo(a): print("hello") --- and --- Module( body=[ FunctionDef( name='foo', args=arguments( posonlyargs=[], args=[ arg(arg='a')], kwonlyargs=[], kw_defaults=[], defaults=[]), body=[ Expr( value=Call( func=Name(id='print', ctx=Load()), args=[ Constant(value='hello')], keywords=[]))], decorator_list=[])], type_ignores=[]) --- The latter is the same as the former, just in the AST form. That's what we ask people to do with type annotations currently - write them in the AST form.
Steve
-- Best regards, Paul mailto:pmiscml@gmail.com

I was +0.5 on the arrow syntax for `Callable`. It seemed like a nice short hand but understood the arguments against it in the vain of "There should be one-- and preferably only one --obvious way to do it." But
Absolutely convinced me. +1 - Caleb On Fri, Feb 19, 2021 at 8:45 AM Paul Sokolovsky <pmiscml@gmail.com> wrote:

On Fri, Feb 19, 2021 at 07:35:19PM +0300, Paul Sokolovsky wrote:
Pretty much all of that is either personal subjective judgement, or factually untrue. People will need to learn two syntaxes, because they will have to deal with legacy code using the old syntax. People are already learning and using annotations, and have been for years.
We can already subclass Callable.
The difference between "(int, str) -> int" and "Callable[[int, str], int]" is the same as difference __str__ and __repr__.
A better analogy is the difference between a binary operator versus a function of two arguments: a ^ b bitwise_xor(a, b) The binary operator looks nicer and is terser and more compact, but function notation is more self-documenting.
I don't think so.
I think that's nonsense. Aside from the difference between square brackets and round brackets, `Callable[int, str]` is just a function call. If you think that's "unwieldy, ugly", wait until you try writing some actual Python code, it is full of function calls. It is reasonable to want a more terse and compact syntax for functions, but on the other hand, function parameters that take functions are definitely a relatively narrow niche. More compact syntax is a Nice To Have, not a Must Have. Paul then claims that having to write `Callable[int, str]` in an annotation is equivalent to writing AST: [added indentation to make the structure easier to see]
I can't take that argument seriously. How can you possibly claim that writing an annotation like `Callable[int, str]` is "the same as" writing that deeply-nested 20-line AST? -- Steve

Abdulla Al Kathiri writes:
The main problem is that the second already exists, and the first doesn't, while the first adds no new power to the language, and isn't enough more readable (and some would argue less readable, expecially in the multiple "lots of irritating parentheses" form) than the "lambda" version. While it's not a good idea to take the Zen too seriously, "There should be one-- and preferably only one --obvious way to do it." is often good advice. "Although that way may not be obvious at first unless you're Dutch." means that often that way must be taught to most developers, with "lambda" being an extreme case since very few of us come from the Lisp, Haskell, or Mathematical Logic worlds any more, so references to lambda are infrequent. A small issue is that with a different value, "f(x -> V)" is also possibly a typo for "f(x) -> V", and likely to occur if you have automagic parenthesis matching in your editor. In general, Python's designers prefer (and try to encourage) a style emphasizing building up complex applications from relatively small *named* functions, rather than large monolithic blocks of code. Random's cavil about warty keywords notwithstanding, I kinda like my idea of using a "def expression" to pass a local function as a keyword argument. I wouldn't be surprised if Guido pops up to say "I thought of that in 1998, but it was too cute by half", though. :-) One could argue that this fits the typical human brain well, with its ability to handle chunked data in groups of 7 +/- 2 items. It's unarguable that Python has become very popular, and that its fans are quite devoted to it. Something about this style is capturing them! I don't speak for Guido or any other authoritative voices, that's just my take.

On Wed, 17 Feb 2021 at 18:30, Ethan Furman <ethan@stoneleaf.us> wrote:
Just my 2c, I don't find lambda verbose at all, quite like it. But I wish Python allowed for multi-line lambda functions... somehow. Why? If you need to have a callback function that takes 2 to 5 lines of code, then (1) current lambda doesn't allow it, (2) inline named function, defined earlier, is too verbose IMHO (code style dictates it needs two blank lines, one before, one after, plus need to have a name), and also somewhat breaks the flow of reading code. A multi-line lambda would be able to fill the gap, between too big for single line lambda, but too small to justify its own def xxx(). Sorry, I don't have any concrete proposal, just a vague wish.

On Wed, Feb 17, 2021 at 07:03:55PM +0000, Gustavo Carneiro wrote:
Just my 2c, I don't find lambda verbose at all, quite like it.
But I wish Python allowed for multi-line lambda functions... somehow.
Python allows for multi-*line* lambda: lambda key, value, condition, sep='', default='': ( compute_prefix(key) + sep.join([str(expression or default) for obj in lookup(key, value) if condition(obj)] ) + compute_suffix(key) ) What it doesn't allow is multi-*statement* lambda; lambda is limited to a single expression. Although I have heard from Ruby enthusiasts that the ability to write large, complex, multi-statement anonymous block functions is really useful, its not something I can personally say I have missed. I think that once you get past a fairly simple one-line expression, anything else ought to be tested; and that requires making it a named function at the top level so that doctest or unittest can see it. -- Steve

On Thu, Feb 18, 2021 at 8:46 PM Steven D'Aprano <steve@pearwood.info> wrote:
I think I can kinda sympathize with that perspective. Just like you sometimes have an elif block where "a bunch of stuff happens", sometimes you have a callback function that is only used by one other function. It cannot be a block in current Python because it's a callback, but it doesn't *really* have a meaningful name outside that of the enclosing function. On other hand, writing an inner function and using the throwaway name `fn` for it requires two extra characters. OK, maybe 4 characters since it is both defined and then used. Of course, exact character count depends on the hypothetical syntax of a "multi-statement lambda" ... but it amounts to "no big deal" in existing Python, in any case.

On 2021-02-13 14:33, Christopher Barker wrote:
Agreed. It isn't too important at this point, but I'd also skip the punctuation and add an expression version of def: def named_function(x, y): return x * y anonymous_function = def x, y: x * y Parentheses on the parameter list could be allowed as well. Javascript has (too much) flexibility in this area, but I wouldn't mind Python loosening slightly to use the keyword it probably should have in the beginning. -Mike

11.02.21 13:24, J. Pic пише:
This syntax is ambiguous. if (y): len(y): What does the first colon mean? You cannot say until you read the second colon. It is difficult to parse for human and computer. While the current PEG parser perhaps can handle this, it still makes parsing slower and the code more errorprone. Lambda is a questionable feature at all. With support of comprehensions, local functions, the operator and functools modules there are not many use cases for lambda expression. They are supported, well, but it is not significant part of the language.

On Sun, Feb 14, 2021 at 4:26 AM Serhiy Storchaka <storchaka@gmail.com> wrote:
Thank you -- I'm not quite sure they are "questionable", but they do have limited use in the language, and far less use then they did back in the early days of Python. In fact, most of the uses I've seen of lambda in recent code (particularly from newbies) is totally unnecessary. If the only thing this proposal is about is a way to create small anonymous functions without using the keyword "lambda" -- it is pretty darn pointless. And frankly, this compact notation is a lot harder (for me at least) to parse at a glance -- "lambda" may be a strange and confusing word for newbies, but it's easy to look up, and it's really obvious that *something* is going on there. Whereas parentheses are used all over the place, and are often optional. And more "line noise"-like symbols like => isn't really going to help. In fact, I've only written a smattering of C, but it still requires some extra thinking to identify where a function is being defined -- a keyword (like def) would be so much more clear to me. Final point: Python has been around a long time, there's a lot of code already written -- any changes to syntax should only be ones that add real functionality or expressiveness -- a slightly-easier-to-write (and maybe read) anonymous function syntax is nowhere near that threshold. -Chris B -- Christopher Barker, PhD (Chris) Python Language Consulting - Teaching - Scientific Software Development - Desktop GUI and Web Development - wxPython, numpy, scipy, Cython

Hello, On Thu, 11 Feb 2021 12:24:55 +0100 "J. Pic" <jpic@yourlabs.org> wrote:
What will be the meaning of {(): [12]} ? Hint: it will be a dictionary of empty tuple mapping to a list, where do you see lambda here? Generally, if you have an idea like that, please go ahead and implement it with one of the existing macro engines for Python. That alone should give yourself more insight how viable it is. Here's tutorial to get you started: https://github.com/aroberge/ideas#usage -- Best regards, Paul mailto:pmiscml@gmail.com

Oh, I didn't think of it, thank you Paul. Inspiration from JavaScript was not a good idea. Instead, would like to propose to make the "def" keyword optional like in bash: foo(x): len(x) Would be equivalent to: foo = lambda x: len(x) Would that work? On Thu, Feb 11, 2021 at 12:24 PM J. Pic <jpic@yourlabs.org> wrote:
-- ∞ On Thu, Feb 11, 2021 at 12:48 PM Paul Sokolovsky <pmiscml@gmail.com> wrote:
-- ∞

I think you also need return, and double space pound space qa to pass linters: def foo(): return 1 # noqa Instead of foo = lambda: 1 And this proposal: foo(): 1 The benefit is just to get more out of the 80 characters when we want to define a short callback. I understand this is not a life changing proposal, but was wondering if it was "nice enough" to be worth proposing. Le jeu. 11 févr. 2021 à 15:43, Steven D'Aprano <steve@pearwood.info> a écrit :

On Thu, Feb 11, 2021, at 06:48, Paul Sokolovsky wrote:
This could be solved with parentheses, but I think it'd probably be better to use similar syntax to C#, Java, and Javascript instead, and use () -> [12] or () => 12... It's worth noting that all three of these are later additions to their respective languages, and they all have earlier, more difficult, ways of writing nested functions within expressions. Their designers saw the benefit of an easy lambda syntax, why don't we? It also may be worth looking at what it would take to allow asynchronous lambdas. Syntactically, while "any lambda containing await" is tempting, the lack of static typing means that we need a way to specify async lambdas that do not contain await. Javascript prefixes the argument list with async [i.e. "async () => ..." or "async onearg => ..."], as does C# even though it could in principle get away without doing so because of static typing.

On Thu, Feb 11, 2021 at 8:58 PM Random832 <random832@fastmail.com> wrote:
Agreed. I'd prefer the JavaScript solution, since -> already has a different meaning in Python return *type*. We could use -> to simplify typing.Callable, and => to simplify lambda.
Probably we were blinded by the endless search for for multi-line lambdas. It's not too late.
Makes sense. -- --Guido van Rossum (python.org/~guido) *Pronouns: he/him **(why is my pronoun here?)* <http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-c...>

Hello, On Thu, 11 Feb 2021 21:36:25 -0800 Guido van Rossum <guido@python.org> wrote:
Great to hear there's no desire to stray away from JavaScript just for the purpose of being different. I myself would never propose to take any bad ideas from JS, but in some areas, it now leads. And for wider context, it's the same idea with (informal so far) proposal to use "const" for defining *block-local* immutable variables, and "let" for *block-local* mutable vars. This isn't a bad choice on its own, but also matches what JavaScript ended up to have, and would help avoid confusion in wider programming language context. (And yes, that use of "let" does not match its use in pure-functional languages, but JS/Python are different beasts than pure-functional languages). [] -- Best regards, Paul mailto:pmiscml@gmail.com

Hello, On Fri, 12 Feb 2021 09:55:16 +0300 Paul Sokolovsky <pmiscml@gmail.com> wrote:
... And on the 2nd thought, that won't work. The reason it works in JS is that it doesn't have tuples. In Python, "(a, b) => (1, 2)" means "compare a tuple for greater-or-equal". But fear not, we can steal "lambda operator" from Haskell: \(a, b): (1, 2) Or... we can do nothing, and just promote macro usage in Python, because it's trivial to replace "lambda" with actual unicode lambda character (or anything else for that matter, for as long as "anything else" is not an empty string and not ambiguous with already existing constructs): https://aroberge.github.io/ideas/docs/html/lambda.html [] -- Best regards, Paul mailto:pmiscml@gmail.com

On 12/02/2021 07:32, Paul Sokolovsky wrote:
It takes a bit of mental processing to realise this isn't a valid comparison, and then more processing to understand what it does mean; it will definitely be a source of confusion for beginners. The fact that a very respected member of the community got it wrong at first sight suggests that many will do so. If we were going to do this - and I am still on the fence - I think we should avoid anything that reads like it could be confused as an operator.

On Fri, Feb 12, 2021, at 02:23, Paul Sokolovsky wrote:
Nope. greater-or-equal is >=, not =>. And Javascript may not have tuples, but it does have the comma operator.
But fear not, we can steal "lambda operator" from Haskell:
\(a, b): (1, 2)
That's another option [and might be easier to parse], but I think it's less readable.

On Thu, Feb 11, 2021 at 09:36:25PM -0800, Guido van Rossum wrote:
Please no! That will lead to constant confusion for people who can't remember which arrow operator to use. Is -> the return type symbol or the return value symbol? I forsee many Stackoverflow questions "What's the difference between -> and => ?" We've seen Paul mistake => for >= and he's not the only one. We already have chosen -> as the return type symbol in annotations, there is no ambiguity with also using it as the return value symbol. We could even allow both: (values:List[float], arg=0:int -> Type) -> expression There are plenty of popular and influential languages that use the single line arrow -> such as Maple, Haskell, Julia, CoffeeScript, Erlang and Groovy, to say nothing of numerous lesser known and obscure languages. -- Steve

Hello, On Sun, 14 Feb 2021 18:36:14 +1100 Steven D'Aprano <steve@pearwood.info> wrote:
Well, my mistake is based on the fact that I don't spend high-level neurons on remembering mundane low-level things, like order of characters if the "greater or equals" operator. Instead, low-level hands motor function neurons get it right when I type (most of the time ;-)). It's the same as I (and many other people I'm sure) don't remember phone numbers nowadays - why, if modern phones well remember them themselves, transfer from one instance to another, etc. Bottom line: after not too long practice, nobody would confuse ">=" and "=>", as they're different on their usage context (picked up subconsciously).
We already have chosen -> as the return type symbol in annotations, there is no ambiguity with also using it as the return value symbol.
You're mastermind to claim it like that. I for one wasn't sure there's no grammar-level ambiguity. Perhaps now I can say: if an arrow function appears in the type annotation position, then well, it's a type. That should work for the parser algorithm. But there another problem, on humans' side. For humans, it's very helpful when different concept look somewhat different. And it's very helpful to use different arrows for values vs types.
We could even allow both:
(values:List[float], arg=0:int -> Type) -> expression
I for one can't parse that (didn't have a morning coffee, but suspect there's a typo/thinko). Btw, I'm not sure about function values, but IMHO, type notation should always use parens for arguments, e.g. "(int) -> int".
The question is how many of those language have first-class type literals, and how many use the same notation for function literals and type literals. [] -- Best regards, Paul mailto:pmiscml@gmail.com

def func(x: int, y: int, f: (int, int) -> int) -> int: return f(x, y) print(func(1, 4, (x, y) -> x + y)) #Output: 5 I think we can still use the same syntax for both typing.Callable and lambda. It would act like Callable if it comes after the “:” in annotations or after the “->” in function return annotation. After assignment or using it directly as an argument, then it acts like lambda. func: (str, str) -> None = (text1, text2) -> print(text1 + text2) Same syntax, but communicates two different things. I don’t see any problem with this. func: (str, str) -> None = (text1, text2) => print(text1 + text2) is not bad either to be honest.

On Sun, Feb 14, 2021 at 11:23:59AM +0300, Paul Sokolovsky wrote:
That would be just great if code was written more than it is read. ("Doesn't matter that people reading the code confusion the symbols, nobody reads it; what matters is that my hands know what to type.") Or if we had a rule that only Python developers with a minimum of 10 years experience are allowed to use it. [...]
If I'm wrong, I'm sure somebody will point that out. I'm not frightened of making bold claims that turn out to be wrong: that just means I have learned something new. (Or something old that I forgot.) My reasoning is this: The arrow return annotation in def functions is only legal outside of the parameter list, and if it is there at all, it must immediately follow the parameter list. def func(params) -> ret_expression: So any time you see a def with a parameter list, inside the parameter list any arrows have to be the arrow function syntax. The first arrow immediately following the parameter list must be the return annotation, and any arrows following that must be part of ret_expression which could of course include more arrow functions. No matter how complicated the parameter list gets, the parser will never expect that return annotation arrow until the parameter list has completed and the closing parenthesis has been seen. Even if it is an unreadable mess to the human reader, to the interpreter it ought to be completely unambiguous: until you hit that closing parenthesis, you're still in the parameter list and so no arrow can be the function annotation arrow. Am I right so far? Things get a bit more complex if the arrow functions themselves can include annotations. Lambdas don't, so perhaps these won't either. But if they do, I have assumed a syntax like this: (a:T, b:T, c:T -> T) -> body where the return type annotation is inside the bracketed argument list. Each of those "T"s are, naturally, arbitrary expressions, so they could also include arrow functions. But the parser can always tell if it is looking inside the parameter list, and if so, if it is a default value, an annotation, the return annotation, or if it has reached the end of the parameter list and is now in the body. And of course, nothing in the arrow function (not the parameter annotations, default values, the return annotation, or the body) can contain a def with its `->` arrow. So I am: - very confident that there is no ambiguity between def function return annotations and arrow functions if they don't include annotations (as lambdas do not); - not so confident if they do support annotations; - but in that case, it ought to be resolvable. There you go: I have boldly laid my neck out on the chopping block. If I am wrong, I will be happy to be corrected.
But there another problem, on humans' side. For humans, it's very helpful when different concept look somewhat different.
And it is also very helpful to have similar concepts look similar. Return a value? The critical term here is **return**. Return type? The critical term here is also **return**.
And it's very helpful to use different arrows for values vs types.
Why is it helpful? Helpful to whom? I can see that it would be helpful to have different arrows if there were cases where the reader wasn't sure whether they were looking at an annotation or an arrow function, but I don't think that will ever be the case.
Yes, I swapped the order of the default value and the type annotation, it should read: (values:List[float], arg:int=0 -> Type) -> expression Sorry for the confusion. In case anyone is still having trouble parsing that: # lambda version lambda values, arg=0: expression # becomes arrow function (values, arg=0) -> expression # add parameter annotations (values:List[float], arg:int=0) -> expression # and the return type of the function body (expression) (values:List[float], arg:int=0 -> T) -> expression
What is this type notation you are talking about, and how is it relevant to Python and this proposal?
I don't think that question either makes sense or is important. We are not limited to "type literals", whatever that means to you. (To me, that would mean built-in reserved words for types, like `integer`, `real`, `boolean` in Pascal.) Types can be expressions, like `List[object]` or `Union[Spam, Eggs]`. -- Steve

Be bold, they say... On Mon, Feb 15, 2021 at 02:13:38AM +1100, Steven D'Aprano wrote:
Okay, there is an ambiguity, if arrow function syntax includes annotations with the syntax I suggested. I had: (values:List[float], arg:int=0 -> Type) -> expression Using that syntax, there is an ambiguous case: (arg=(a, b) -> T) -> expression That could mean: * Default value of arg is the arrow function `(a, b) -> T`; * Or the default value of arg is the tuple `(a, b)`, and the arrow function has the return type T. This may suggest that, like lambda, we should just not allow annotations in arrow functions; or that we need a better way to include the return annotation. The third fix is to use `=>` for the arrow functions, but this has many down-sides, as previously discussed. Anyway, the rest of my claim still stands (I think): if arrow functions don't include annotations there is no ambiguity between function annotations and arrow functions. -- Steve

Hello, On Thu, 11 Feb 2021 23:57:16 -0500 Random832 <random832@fastmail.com> wrote: []
No, it can't be - parentheses are optional, and without them, "(): [12]" and "{(): [12]}" would mean wildly different things. And any programming language should aim to minimize and avoid such cases. It's a similar concern which was raised for PEP642 (pattern matching alternatives), where syntax looking related to sets, was suddenly repurposed to mean dicts instead. Such cases are highly confusing. [] -- Best regards, Paul mailto:pmiscml@gmail.com

On 2021-02-11 03:24, J. Pic wrote:
I don't see any need for this. It's even more cryptic than "lambda" because at least lambda is a word you can look up. This is just inscrutable punctuation. Using different punctuation like "=>" doesn't help. The only thing that would be better than lambda is a less confusing keyword. So like "func x: x+2" would be better than "lambda x: x+2". That probably won't happen because no one wants to add new keywords. But adding new non-keyword ways to do this isn't worth it just to save a few keystrokes. -- Brendan Barnwell "Do not follow where the path may lead. Go, instead, where there is no path, and leave a trail." --author unknown

I actually like the “(x, y=7) => x + y” and “async (x, y) => asyncio.sleep(x + y)” for both normal and async anonymous functions respectfully. I have natural aversion to the word lambda for some reason. The normal anon function has “return” implicitly, and the async anon function has “return” implicitly as well. Usage: f1 = (x, y=7) => x + y f1(3) outputs 10 f2 = async (x, y) => asyncio.sleep(x + y) async def main(): coro = f2(3, 7) await coro return “waited 10 seconds” result = asyncio.run(main()) print(result) # outputs “waited 10 seconds” Also, this is very close to what I brought back to discussion some time ago, which is typing.Callable.. instead of =>, we do -> for it. Correct me guys if you find any mistakes in the above. Python with those new proposal and Match Pattern will be so much more elegant. Abdulla Sent from my iPhone

On Fri, 12 Feb 2021 at 09:26, Abdulla Al Kathiri <alkathiri.abdulla@gmail.com> wrote:
I actually like the “(x, y=7) => x + y” and “async (x, y) => asyncio.sleep(x + y)” for both normal and async anonymous functions respectfully.
I think it's a reasonable syntax, although it could be over-used. That's not an issue with the syntax, though - *anything* can be over-used :-) Experience with similar syntax in other languages suggests this would be useful.
I have natural aversion to the word lambda for some reason.
It does seem to cause people (including me!) a lot more problems than one would expect, on the face of it. Maybe because it's not a common term outside of computer science? But the endless debates over alternative keywords have never come up with anything else that people can agree on.
I'm not sure what the use cases would be for an async lambda - the key is that it's not named, so the above isn't a good example as it's just as easy to write async def f2: return asyncio.sleep(x+y) (Excuse any errors here, I'm not that familiar with asyncio). If there are good use cases, I think it makes sense to include async lambda in any proposal. I'm not saying that it isn't useful, just that it doesn't have all the history that (non-async) lambda does, so the argument in favour of async lambda isn't as strong. Use cases are key - adding it "just because we can" would just make the proposal more controversial, and then the whole thing could collapse over something secondary. Ultimately, this would need someone to write a PEP. Paul

I am not that familiar with asyncio either. I only wrote a few utility scripts that runs concurrent subprocesses mixed with some blocking functions running in concurrent.ProcessPoolExecutor pool (using asyncio.run_in_executor). That is all what I did with regard asyncio. Your function f2 and my function f2 could be actually normal functions. f2 = (x, y) => asyncio.sleep(x + y). f2(3, 7) will just return a coroutine that can be awaited on just fine. To be honest, i don’t even know what the purpose would be with async lambda unless someone with more experience can give us a use case. My guess is that it may be useful to use it as an argument to another async function. Since we can write shortened normal functions (lambda), shortened generator function (lambda with generator expression), people might ask why Python doesn’t have shortened async function? But maybe that is not a good question to begin with? Lambda reminds me of the half life time of isotopes. The other day, I was struggling to teach this to my cousin in elementary school. I just told him to imagine it like def _(args): return something. Assign it to a variable and that variable replaces the underscore. He got it but he found it weird. Sent from my iPhone

Fair enough. Whoever writes a PEP for this will need to do the relevant research and present the arguments in detail. But until someone's ready to write that PEP, we can continue discussing on the assumption that if someone finds the async version useful, they'll speak up. Paul On Fri, 12 Feb 2021 at 11:24, Abdulla Al Kathiri <alkathiri.abdulla@gmail.com> wrote:

On Fri, Feb 12, 2021 at 7:57 PM Brendan Barnwell <brenbarn@brenbarn.net> wrote:
sigh. That argument again? I just asked Google about "javascript =>" and got a bunch of perfectly good results. Some said "arrow function", others have "=>" in the title: https://stackoverflow.com/questions/24900875/whats-the-meaning-of-an-arrow-f... Yes, you CAN search for punctuation. Please can this argument die? ChrisA

On 2021-02-12 03:18, Chris Angelico wrote:
Okay, fine, drop that argument. It doesn't matter. The point is that we currently have a way to write anonymous functions and this proposal adds NO BENEFIT WHATSOEVER except that instead of typing "lambda" you type two parentheses, thus saving you a grand total of two keystrokes (you need to hit shift to get the parentheses, but not to type "lambda") to get something that doesn't look any less cryptic. Also the fact that JavaScript does something is evidence that it's probably not a good idea. :-) I just don't understand what makes people think that "(a, b): a+b" or "(a, b) => a+b" or any of these other variants has any advantage at all over "lambda a, b: a+b". Yes, "lambda" is cryptic and mysterious, but so are all these alternatives. They don't solve any problems or allow anything that wasn't already possible and they would just clutter up the language. -- Brendan Barnwell "Do not follow where the path may lead. Go, instead, where there is no path, and leave a trail." --author unknown

On Fri, Feb 12, 2021 at 1:00 AM Brendan Barnwell <brenbarn@brenbarn.net> wrote:
Is this really what this is all about? removing that word? I do think that adding a parens around the parameters would make it a bit more clear, but it currently illegal: In [18]: lambda(x, y): x + y File "<ipython-input-18-0f5b071bce98>", line 1 lambda(x, y): x + y ^ SyntaxError: invalid syntax
So like "func x: x+2" would be better than "lambda x: x+2". That probably won't happen because no one wants to add new keywords.
There seems to be a frequent objection to the word "lambda" -- personally, I found it cryptic, but it's not hard to remember, and it IS easy to look up. But if you don't like that word, why not "def"? Every place I've tried to use "def" where "lambda" is legal, it's a syntax error. So we could use the same word. Would that be less confusing? My thought is yes it would , IF we were stating from scratch -- but this would be a lot of churn in code and documentation for very little gain. -Chris B
-- Christopher Barker, PhD (Chris) Python Language Consulting - Teaching - Scientific Software Development - Desktop GUI and Web Development - wxPython, numpy, scipy, Cython

On Sun, Feb 14, 2021 at 9:33 AM Christopher Barker <pythonchb@gmail.com> wrote:
It is currently illegal, but in previous Pythons, it was legal, with different semantics. Python 2.7.16 (default, Oct 10 2019, 22:02:15) [GCC 8.3.0] on linux2 Type "help", "copyright", "credits" or "license" for more information.
ChrisA

Hello, On Sat, 13 Feb 2021 14:33:43 -0800 Christopher Barker <pythonchb@gmail.com> wrote:
There seems to be a bit too many posts downputting the "lambda" keyword, and nobody went for its defense, so let me do that. The "lambda" is perhaps the greatest thing in Python after... after... well, maybe it's the single greatest thing in Python. As someone coming to Python from LISP (many years ago), I really appreciate it, and always considered Python to be "a LISP for real world". So, it's of great utility to people familiar with functional programming, but even of more utility to novices who are not yet - thanks to it, by looking it up, they can get acquainted with the wonderful world of functional programming and history of programming languages. Lambda is a sacred keyword, please don't touch! -- Best regards, Paul mailto:pmiscml@gmail.com

"lambda" is unnecessarily obscure. Beginner: "why is it called lambda?" Teacher: "Don't worry about it, just use it to define a function" I'm not taking a side on whether to change Python, but let's please not lose sight of just how opaque the word "lambda" is. People who know the background of lambda can easily understand using a different word. People who don't know the background are presented with a "magic word" with no meaning. That's not good UI. --Ned. On 2/14/21 11:39 AM, Paul Sokolovsky wrote:

On Tue, 16 Feb 2021 at 16:40, Ned Batchelder <ned@nedbatchelder.com> wrote:
Agreed. When lambda was introduced, "anonymous functions" were not as common in programming, and the most obvious example of their usage was in lisp, where "lambda" was the accepted term. Since then, lisp has not gained much additional popularity, but anonymous functions have appeared in a number of mainstream languages. The syntax is typically some form of "a, b -> a+b" style, and *never* uses the term "lambda". So someone coming to Python with any familiarity with other languages will now find Python's form atypical and obscure. People coming with no experience of other languages will need to have a history lesson to understand why the term is "lambda" rather than "something more obvious". People can, and will, learn Python's syntax. This isn't a major disaster. But if this were a new feature, we'd not be having this discussion, and "lambda" wouldn't even be a consideration. I'm also not taking a side on whether a change is worth the disruption. Personally, I prefer the arrow syntax, but we're not making a decision in a vacuum here. Someone has to make a case (probably in a PEP) if this is going to change, and the trade-offs should be clarified there. Paul

On Tue, Feb 16, 2021 at 11:38:33AM -0500, Ned Batchelder wrote:
That's a bad answer. A better answer that is more appropriate for nearly everyone is "It's Greek letter, like pi that you may remember from maths class. In some technical computer science, the Greek L, lambda, is used as the symbol for functions." Two sentences, a few seconds to say. At this point the student almost certainly will be either satisfied with the answer, and have learned something new, or will be satisfied with the fact that there is an answer, and promptly forget it because they didn't really care, they just want to know that there is a reason. And for that perhaps one in fifty who go on to ask "Why lambda?", the answer is "They had to choose some letter, and lambda was the one they picked." I don't understand people who are unwilling to explain things. It makes me sad.
You know the approximately 7.4 billion people in the world who aren't native English speakers? And the approximately 5 billion people who speak no English at all? They just said "Welcome to our world!" Honestly, I think this argument about lambda being a magic word is both privileged and silly. Its no more "magic" than tuple, deque, iterator, coroutine, ordinal, modulus, etc, not to mention those ordinary English words with specialised jargon meanings like float, tab, zip, thread, key, promise, trampoline, tree, hash etc. It's just a word. Every single word that we know had "no meaning" to us at some point. None of us were born knowing what "raise" or "hex" means. There is a *ton* of jargon to learn on the way to becoming a decent programmer, I don't know why lambda is singled out for so much hate. Personally I had much more difficulty learning "tuple", or "turple" as I insisted on spelling it for about the first five years. And I still don't know where the word comes from in the first place. Given that it is used in maths, probably Latin, Greek or Arabic. -- Steve

On 16.02.2021 23:13, Greg Ewing wrote:
The Python notation for anonymous function is almost a direct reference to the original notation for such functions in lambda calculus: λx.x+1 ... lambda x: x+1 I think that's an excellent hint for students to look up on this great piece of mathematical logic: https://en.wikipedia.org/wiki/Lambda_calculus and learn something about the foundations of computer science. Why the Greek letter lambda ? Who knows -- mathematicians love Greek letters, logic is λογική in Greek, ... https://en.wikipedia.org/wiki/Lambda_calculus#Origin_of_the_lambda_symbol And, of course, if you don't like anonymous functions, you're always free to give your functions names in Python ;-) -- Marc-Andre Lemburg eGenix.com Professional Python Services directly from the Experts (#1, Feb 17 2021)
Python Projects, Coaching and Support ... https://www.egenix.com/ Python Product Development ... https://consulting.egenix.com/
::: 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 https://www.egenix.com/company/contact/ https://www.malemburg.com/

On Wed, Feb 17, 2021 at 11:13:08AM +1300, Greg Ewing wrote:
Not according to Alonzo Church, who at various times has stated that it was either more or less chosen at random, or that it was derived from Whitehead and Russell's x̂ (x-hat) via ∧x to λx to make it easier for the printers. Either way it wasn't a mistake, but a deliberate choice. It is really remarkable how much attention lambda gets. As far as I know, mathematicians don't ask why Hilbert chose epsilon for his epsilon calculus, and nobody ever asks where "byte" comes from. It is, apparently, a deliberate misspelling of bite, to avoid it being accidently changed to bit. But why *bite*? The first published use of "byte" apparently was in a 1956 IBM memo by Werner Buchholz: "[…] Most important, from the point of view of editing, will be the ability to handle any characters or digits, from 1 to 6 bits long. Figure 2 shows the Shift Matrix to be used to convert a 60-bit word, coming from Memory in parallel, into characters, or 'bytes' as we have called them, to be sent to the Adder serially." The memo already shows that Buchholz and IBM were thinking of multiple bits being a "word", so it's not clear why bytes. There's no ordinary sense that a collection of bits (as in "a bit of stuff") is considered "a bite". Language is fun. -- Steve

On 17/02/21 7:10 am, Steven D'Aprano wrote:
Actually, I think it is -- all those words build on a pre-existing meaning in some way, and in most cases you can trace the etymology back to something the person is most likely already familiar with. Lambda, on the other hand, is a completely fresh arbitrary choice. I agree that the technical meaning has to be taught in any case, though. -- Greg

Ned Batchelder writes:
"lambda" is unnecessarily obscure.
And it should be. It's really only useful as an argument. There's no advantage to foo = (x) -> 1 vs. def foo(x): return 1 except a couple of characters. So what currently looks like some_list.sort(key=lambda e: e[3].priority) would then be some_list.sort(key=(e)->e[3].priority) which is shorter but not particularly more readable (and already has a familiar meaning in C-like languages). It seems to me that two changes to def might be considered: 1. In a one-line def of the form "def foo([arglist]): return EXPR", "return" may be omitted, and the function returns the value of EXPR (rather than None as currently). (As a multiline def, EXPR would be presumed to be evaluated for side effects, and 2. As an actual argument, a one-line def is interpreted not as a positional argument, but as a keyword argument, so that in some_list.sort(def key(e): e[3].priority) the name "key" is not optional, and must match a keyword argument. I suggest 1 for "ordinary" defs as well for consistency, but evidently we could also restrict that usage to "def as keyword argument", and maintain backwards compatibility. 2 could even be independent of 1: some_list.sort(def key(e): return e[3].priority) but that seems excessively verbose. Another possible use case would be in a for loop: for fun in [def fun(): return 1, def fun(): return 2, def fun(): return 3]: do_something_with(fun) where similarly the loop variable needs to match the def.
Beginner: "why is it called lambda?"
Teacher: "Don't worry about it, just use it to define a function"
It me. But it would go like this: Teacher [face lights up at the chance to talk math history]: "You see, ..." Students [in harmony]: "NOOOOOOOOooooooo.......... :-(" [collective sigh] Regards, Steve

On Tue, Feb 16, 2021, at 23:24, Stephen J. Turnbull wrote:
Let's not pretend the key argument being keyword-only isn't a wart. Surely this would be better if it could be some_list.sort(e->e[3].priority).
which is shorter but not particularly more readable (and already has a familiar meaning in C-like languages).
this side point is an argument in favor of using => instead. [and if => can be confused with >=, surely so can -> be confused with >-]
I would like something like this - it's worth noting that C# [and as someone helpfully pointed out, Dart] uses => for this case as well, and the argument about the syntax looking bad when a return type annotation is present is, I think, overblown - return type annotations are almost never needed for a function with a single return statement.

On 2/17/21 8:47 AM, Random832 wrote:
On Tue, Feb 16, 2021, at 23:24, Stephen J. Turnbull wrote:
No need to pretend, it isn't a wart. -1 on removing the lambda keyword. Just because excessive punctuation works for other languages does not mean it's a good fit for Python. -- ~Ethan~

On Wed, 17 Feb 2021 at 15:31, Ethan Furman <ethan@stoneleaf.us> wrote:
If someone comes with a "pythonic" way to lift restrictions on lambda, that could be something for debate, but so far this is just about uglifying it, and creating a new syntax matching exactly what exists today. Moreover I'd like to remind people so much worried about expressiveness in less and less characters that Lambda is much less needed in Python than in similar languages due to the existence of the comprehensions and generator expression constructs. The energy spent here could be focused instead on having an equivalent of comprehensions for "reduce", for example.

On Wed, 17 Feb 2021 at 18:15, Abdulla Al Kathiri < alkathiri.abdulla@gmail.com> wrote:
Well, for m eyes, the above is definetellly "perlonic" . it could be "j" before being Pyrhon. This is Pythonic: def f1(x, y): return x + y def f2(): return 0 def f3(x): return x ** 2 And it took me a while looking at our example to check it was not really fuction composition with default parameters, or what. I mentioned violation of 6 of the first 7 phrases in the famous "zen of Python" - most important of which can be reasonably agreed is the 7th: "Readability counts". If you don't want readability at all in exchange for typing a few keywords (which more and more automatic tools can auto-complete), I'd suggest going for the "forth" language. Abdulla

Hello, On Wed, 17 Feb 2021 18:43:09 -0300 "Joao S. O. Bueno" <jsbueno@python.org.br> wrote:
As said many times already, that's not Pythonic, because "->" is used in Python for return *type* annotation, and thus cannot be used as lambda synonym (without hampering understandability for machines and humans). To illustrate it, (x, y) -> x + y translates to: Callable[[x, y], x + y] while (x, y) => x + y translates to: lambda x, y: x + y Huge difference.
Well, for m eyes, the above is definetellly "perlonic" . it could be "j" before being Pyrhon.
That's unlikely, in Perl it would be something like $x+$y $) ql/x y/. As was said from the very beginning, "(x, y) => x + y" is "JavaScriptonic". For reference, JavaScript is the world's leading programming language, and now even turned out that it has some "good parts" (much later than originally supposed). So, people are looking how to "steal" those good parts. (Just the same as previously, JS "stole" generators from Python). -- Best regards, Paul mailto:pmiscml@gmail.com

I will be very happy if those versions of Callable and anonymous functions exist in Python right now. See how elegant that would look like.. def func(x: int, y: int, f: (int, int) -> int) -> int: return f(x, y) print(func(3, 4, (x, y) => x + y)) #Out: 7 Imagine your mouse is on :func: ‘func’ in VSC or PyCharm and see that you need the third parameter to be of type (int, int) -> int, you can immediately write an anonymous function that mirrors the structure of the annotation but instead of ->, you have =>. Straight forward.

On 2021-02-18 at 18:10:16 +0400, Abdulla Al Kathiri <alkathiri.abdulla@gmail.com> wrote:
Elegant? I realize that this is a contrived scenario, but even if the identifiers x, y, and f were meaningful (e.g., account_balance, socket_descriptor), the signal to noise ratio in that definition makes me cringe. And it only gets worse once I'm not dealing with ints.
If my IDE is that clever, then it can also type "lambda x, y: " for me in addition to showing me that signature. Aside: And then a thousand developers/engineers/maintainers, auditors, and testers (not to mention future me) have to read that anonymous function. Over and over. And over. Unless it's trivial, or simpler, use a def statement, give it a name and a doc string, test it, and reuse it. And if it's that trivial, then trading "lambda" for "->" (or "=>") doesn't matter.

2QdxY4RzWzUUiLuE@potatochowder.com writes:
I'm -1 on the Arrow proposal, but old Lisper that I am I do define functions like that. I would write it: def post_to_auditor( account_balance: PosIntPennies, socket_descriptor: Socket, validator: (PosIntPennies, Socket) -> Bool ) -> Bool: which I don't think is bad at all.[1] Is the S/N really so bad? (Aside from the fact that try as I could I couldn't think of even one reason for passing both account_balance and socket_descriptor to the same user-supplied function, an idea that made my ears ring). I think it's important in these things that we avoid taking toy examples and criticizing them for points that they weren't intended to make. It's also useful to use real code to avoid this kind of criticism. Most of the really strong arguments for syntax changes that I've seen take the stdlib, or some other large body of code (in this case I would bet Sympy would be a candidate) and show how the change improves its expressiveness. Footnotes: [1] Don't ask me about the docstring, I am a game theorist, not an accountant nor a network engineer.

def test(self, func: t.Callable[..., bool], *args, **kwargs) -> Predicate: """ Run a user-defined test function against the value. >>> def test_func(val): ... return val == 42 ... >>> var('f1').test(test_func) :param func: The function to call, passing the dict as the first argument :param args: :param kwargs: Additional arguments to pass to the test function """ return self._build_predicate( lambda lhs, value: func(lhs, *args, **kwargs), Operation.TEST, (self._path, func, args, freeze(kwargs)) ) Becomes .... def test(self, func: (...) -> bool, *args, **kwargs) -> Predicate: """ Run a user-defined test function against the value. >>> def test_func(val): ... return val == 42 ... >>> var('f1').test(test_func) :param func: The function to call, passing the dict as the first argument :param args: :param kwargs: Additional arguments to pass to the test function """ return self._build_predicate( (lhs, value) => func(lhs, *args, **kwargs), Operation.TEST, (self._path, func, args, freeze(kwargs)) ) Sent from my iPhone

Abdulla Al Kathiri writes: Condensing to the parts which are in question,
Yes, it's nicer, but I don't see a win big enough to be worth forcing people who read code to learn two syntaxes for lambda, and two syntaxes for Callable (one of which isn't even syntax). Also, "->" can't be just syntax, if I understand type annotations correctly. It would need to become an object constructor. Then the question would be "are there cases where 'Callable' is not what you want there?", i.e., you want a subclass of Callable. In that case you'd have to use the old syntax anyway. (I don't have an answer to that, but you would need one.) I don't make the rules, but to me if this is the best you can do, you would have to provide evidence that quite a lot of code would benefit from this. Steve

Hello, On Sat, 20 Feb 2021 00:23:13 +0900 "Stephen J. Turnbull" <turnbull.stephen.fw@u.tsukuba.ac.jp> wrote:
People won't learn "two syntaxes for Callable". People shun using Python's current type annotations due to their ugliness and "quick hack without thinking of UX" feel. Only after there will be "int | str" instead of "Union[int, str]", "(int, str) -> int" instead of "Callable[[int, str], int]", "int & const" instead of "Annotated[int, const]" - only then people will start learn and use them.
It depends on how "->" in that role will be implemented. It would be nice to not just hardcode it to "Callable[lhs, rhs]", but at the same time, I'd personally hope we'll avoid yet another dunder either.
There can't be subclass of Callable in the same way as there can't be: class my_foo(type(lambda:0)): pass
The difference between "(int, str) -> int" and "Callable[[int, str], int]" is the same as difference __str__ and __repr__. "Callable" syntax is effectively an internal representation of the type annotation information. And currently, the people have to write that verbose, unwieldy, ugly representation (which normally would be needed only for debugging purposes) manually. What we need is pleasant surface syntax for type annotations in Python. So no, __str__ vs __repr__ comparison doesn't do fairness to it. The difference is the same as between: --- def foo(a): print("hello") --- and --- Module( body=[ FunctionDef( name='foo', args=arguments( posonlyargs=[], args=[ arg(arg='a')], kwonlyargs=[], kw_defaults=[], defaults=[]), body=[ Expr( value=Call( func=Name(id='print', ctx=Load()), args=[ Constant(value='hello')], keywords=[]))], decorator_list=[])], type_ignores=[]) --- The latter is the same as the former, just in the AST form. That's what we ask people to do with type annotations currently - write them in the AST form.
Steve
-- Best regards, Paul mailto:pmiscml@gmail.com

I was +0.5 on the arrow syntax for `Callable`. It seemed like a nice short hand but understood the arguments against it in the vain of "There should be one-- and preferably only one --obvious way to do it." But
Absolutely convinced me. +1 - Caleb On Fri, Feb 19, 2021 at 8:45 AM Paul Sokolovsky <pmiscml@gmail.com> wrote:

On Fri, Feb 19, 2021 at 07:35:19PM +0300, Paul Sokolovsky wrote:
Pretty much all of that is either personal subjective judgement, or factually untrue. People will need to learn two syntaxes, because they will have to deal with legacy code using the old syntax. People are already learning and using annotations, and have been for years.
We can already subclass Callable.
The difference between "(int, str) -> int" and "Callable[[int, str], int]" is the same as difference __str__ and __repr__.
A better analogy is the difference between a binary operator versus a function of two arguments: a ^ b bitwise_xor(a, b) The binary operator looks nicer and is terser and more compact, but function notation is more self-documenting.
I don't think so.
I think that's nonsense. Aside from the difference between square brackets and round brackets, `Callable[int, str]` is just a function call. If you think that's "unwieldy, ugly", wait until you try writing some actual Python code, it is full of function calls. It is reasonable to want a more terse and compact syntax for functions, but on the other hand, function parameters that take functions are definitely a relatively narrow niche. More compact syntax is a Nice To Have, not a Must Have. Paul then claims that having to write `Callable[int, str]` in an annotation is equivalent to writing AST: [added indentation to make the structure easier to see]
I can't take that argument seriously. How can you possibly claim that writing an annotation like `Callable[int, str]` is "the same as" writing that deeply-nested 20-line AST? -- Steve

Abdulla Al Kathiri writes:
The main problem is that the second already exists, and the first doesn't, while the first adds no new power to the language, and isn't enough more readable (and some would argue less readable, expecially in the multiple "lots of irritating parentheses" form) than the "lambda" version. While it's not a good idea to take the Zen too seriously, "There should be one-- and preferably only one --obvious way to do it." is often good advice. "Although that way may not be obvious at first unless you're Dutch." means that often that way must be taught to most developers, with "lambda" being an extreme case since very few of us come from the Lisp, Haskell, or Mathematical Logic worlds any more, so references to lambda are infrequent. A small issue is that with a different value, "f(x -> V)" is also possibly a typo for "f(x) -> V", and likely to occur if you have automagic parenthesis matching in your editor. In general, Python's designers prefer (and try to encourage) a style emphasizing building up complex applications from relatively small *named* functions, rather than large monolithic blocks of code. Random's cavil about warty keywords notwithstanding, I kinda like my idea of using a "def expression" to pass a local function as a keyword argument. I wouldn't be surprised if Guido pops up to say "I thought of that in 1998, but it was too cute by half", though. :-) One could argue that this fits the typical human brain well, with its ability to handle chunked data in groups of 7 +/- 2 items. It's unarguable that Python has become very popular, and that its fans are quite devoted to it. Something about this style is capturing them! I don't speak for Guido or any other authoritative voices, that's just my take.

On Wed, 17 Feb 2021 at 18:30, Ethan Furman <ethan@stoneleaf.us> wrote:
Just my 2c, I don't find lambda verbose at all, quite like it. But I wish Python allowed for multi-line lambda functions... somehow. Why? If you need to have a callback function that takes 2 to 5 lines of code, then (1) current lambda doesn't allow it, (2) inline named function, defined earlier, is too verbose IMHO (code style dictates it needs two blank lines, one before, one after, plus need to have a name), and also somewhat breaks the flow of reading code. A multi-line lambda would be able to fill the gap, between too big for single line lambda, but too small to justify its own def xxx(). Sorry, I don't have any concrete proposal, just a vague wish.

On Wed, Feb 17, 2021 at 07:03:55PM +0000, Gustavo Carneiro wrote:
Just my 2c, I don't find lambda verbose at all, quite like it.
But I wish Python allowed for multi-line lambda functions... somehow.
Python allows for multi-*line* lambda: lambda key, value, condition, sep='', default='': ( compute_prefix(key) + sep.join([str(expression or default) for obj in lookup(key, value) if condition(obj)] ) + compute_suffix(key) ) What it doesn't allow is multi-*statement* lambda; lambda is limited to a single expression. Although I have heard from Ruby enthusiasts that the ability to write large, complex, multi-statement anonymous block functions is really useful, its not something I can personally say I have missed. I think that once you get past a fairly simple one-line expression, anything else ought to be tested; and that requires making it a named function at the top level so that doctest or unittest can see it. -- Steve

On Thu, Feb 18, 2021 at 8:46 PM Steven D'Aprano <steve@pearwood.info> wrote:
I think I can kinda sympathize with that perspective. Just like you sometimes have an elif block where "a bunch of stuff happens", sometimes you have a callback function that is only used by one other function. It cannot be a block in current Python because it's a callback, but it doesn't *really* have a meaningful name outside that of the enclosing function. On other hand, writing an inner function and using the throwaway name `fn` for it requires two extra characters. OK, maybe 4 characters since it is both defined and then used. Of course, exact character count depends on the hypothetical syntax of a "multi-statement lambda" ... but it amounts to "no big deal" in existing Python, in any case.

On 2021-02-13 14:33, Christopher Barker wrote:
Agreed. It isn't too important at this point, but I'd also skip the punctuation and add an expression version of def: def named_function(x, y): return x * y anonymous_function = def x, y: x * y Parentheses on the parameter list could be allowed as well. Javascript has (too much) flexibility in this area, but I wouldn't mind Python loosening slightly to use the keyword it probably should have in the beginning. -Mike

11.02.21 13:24, J. Pic пише:
This syntax is ambiguous. if (y): len(y): What does the first colon mean? You cannot say until you read the second colon. It is difficult to parse for human and computer. While the current PEG parser perhaps can handle this, it still makes parsing slower and the code more errorprone. Lambda is a questionable feature at all. With support of comprehensions, local functions, the operator and functools modules there are not many use cases for lambda expression. They are supported, well, but it is not significant part of the language.

On Sun, Feb 14, 2021 at 4:26 AM Serhiy Storchaka <storchaka@gmail.com> wrote:
Thank you -- I'm not quite sure they are "questionable", but they do have limited use in the language, and far less use then they did back in the early days of Python. In fact, most of the uses I've seen of lambda in recent code (particularly from newbies) is totally unnecessary. If the only thing this proposal is about is a way to create small anonymous functions without using the keyword "lambda" -- it is pretty darn pointless. And frankly, this compact notation is a lot harder (for me at least) to parse at a glance -- "lambda" may be a strange and confusing word for newbies, but it's easy to look up, and it's really obvious that *something* is going on there. Whereas parentheses are used all over the place, and are often optional. And more "line noise"-like symbols like => isn't really going to help. In fact, I've only written a smattering of C, but it still requires some extra thinking to identify where a function is being defined -- a keyword (like def) would be so much more clear to me. Final point: Python has been around a long time, there's a lot of code already written -- any changes to syntax should only be ones that add real functionality or expressiveness -- a slightly-easier-to-write (and maybe read) anonymous function syntax is nowhere near that threshold. -Chris B -- Christopher Barker, PhD (Chris) Python Language Consulting - Teaching - Scientific Software Development - Desktop GUI and Web Development - wxPython, numpy, scipy, Cython
participants (26)
-
2QdxY4RzWzUUiLuE@potatochowder.com
-
Abdulla Al Kathiri
-
Andy Challis
-
anthony.flury
-
Brendan Barnwell
-
Caleb Donovick
-
Chris Angelico
-
Christopher Barker
-
David Mertz
-
Ethan Furman
-
Greg Ewing
-
Guido van Rossum
-
Gustavo Carneiro
-
J. Pic
-
Joao S. O. Bueno
-
M.-A. Lemburg
-
Mike Miller
-
MRAB
-
Ned Batchelder
-
Paul Moore
-
Paul Sokolovsky
-
Random832
-
Rob Cliffe
-
Serhiy Storchaka
-
Stephen J. Turnbull
-
Steven D'Aprano