Alternative syntax for Python's lambda
LWN.net needs you! Without subscribers, LWN would simply not exist. Please consider signing up for a subscription and helping to keep LWN publishing |
The Python lambda keyword, which can be used to create small, anonymous functions, comes from the world of functional programming, but is perhaps not the most beloved of Python features. In part, that may be because it is somewhat clunky to use, especially in comparison to the shorthand notation offered by other languages, such as JavaScript. That has led to some discussions on possible changes to lambda in Python mailing lists since mid-February.
Background
This is far from the first time lambda has featured in discussions in the Python community; the search for a more compact and, perhaps, more capable, version has generally been the focus of the previous discussions. Even the name "lambda" is somewhat obscure; it comes from the Greek letter "λ", by way of the lambda calculus formal system of mathematical logic. In Python, lambda expressions can be used anywhere a function object is needed; for example:
>>> (lambda x: x * 7)(6) 42
In that example, we define an anonymous function that "multiplies" its argument by seven, then call it with an argument of six. But, of course, Python has overloaded the multiplication operation, so:
>>> (lambda x: x * 7)('ba') 'bababababababa'
Meanwhile, lambda can be used in place of def, though it may be of dubious value to do so:
>>> incfunc = lambda x: x + 1 >>> incfunc(37) 38 # not much different from: >>> def incfunc(x): ... return x + 1 ... >>> incfunc(37) 38
Lambdas are restricted to a single Python expression; they cannot contain statements, nor can they have type annotations. Some of the value of the feature can be seen in combination with some of the other functional-flavored parts of Python. For example:
>>> list(filter(lambda x: x % 2 == 1, range(17))) [1, 3, 5, 7, 9, 11, 13, 15]
There we use the filter() function to create an iterator, then use list() to produce a list of the first eight odd numbers, with a lambda providing the test function. Over time, though, other Python features supplanted these uses for lambda expressions; the same result as above can be accomplished using a list comprehension:
>>> [ x for x in range(17) if x % 2 == 1 ] [1, 3, 5, 7, 9, 11, 13, 15]
The most obvious use of lambda may be as key parameters to list.sort(), sorted(), max()/min(), and the like. That parameter can be used to extract a particular attribute or piece of each object in order to sort based on that:
>>> sorted([ ('a', 37), ('b', 23), ('c', 73) ], key=lambda x: x[1]) [('b', 23), ('a', 37), ('c', 73)]
Arrow operators?
A thread about "mutable defaults" on the python-list mailing list made its way over to python-ideas when James Pic posted a suggestion for an alternate lambda syntax. His ultra-terse syntax did not strike a chord with the others participating in the thread, but it led "Random832" to suggest looking at the "->" or "=>" arrow operators used by other languages, such as C#, Java, and JavaScript.
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?
Former Python benevolent dictator Guido van Rossum 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.
" He also answered the question by suggesting that the
"endless search for for multi-line lambdas
" may have derailed
any kind of lambda-simplification effort. Van Rossum declared
multi-line lambda expressions "un-Pythonic" in a blog post back in 2006, but in
the thread he said that
it is not too late to add some kind of simplified lambda.
Steven D'Aprano was concerned
about having two separate "arrow" operators. "That will lead to
constant confusion for people who can't
remember which arrow operator to use.
" He said that the
"->" symbol that is already in use for the annotation of return types could also be used
to define anonymous functions. It is also a well-known idiom:
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.
He also posted a lengthy analysis of how both uses of the single-line arrow could coexist, though it turned out that there is a parsing ambiguity if type annotations are allowed in "arrow functions" (i.e. those defined using the single-line arrow). One can perhaps be forgiven for thinking that the example he gives is not entirely Pythonic, however:
(values:List[float], arg:int=0 -> Type) -> expression[...] 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
The obscurity of the name "lambda" also came up. Brendan Barnwell lamented the choice of the name as confusing, while Ned Batchelder called it "opaque":
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.
But, as D'Aprano pointed out, it is far from the only jargon that Python (and other language) programmers will need to pick up:
[It's] 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.
While Paul Sokolovsky is a big fan of the lambda keyword, he does think that differentiating between the two uses of the arrow notation (the existing use for return types and a possible future use for defining short functions) is important. He thinks it would be better to use two different arrows; for defining functions, he is in favor of the double-line arrow (=>) instead.
Proof of concept
To demonstrate the idea, he came up with some proof-of-concept code that implements the double-line arrow as a lambda replacement. Here are some examples that he gave:
>>> f = (a, b) => a + b # not actual Python syntax >>> print(f(1, 2)) 3 >>> print(list(map((x) => x * 2, [1, 2, 3, 4]))) # nor this [2, 4, 6, 8]
Cade Brown did not like the double-line arrow, on general principles, but Sokolovsky reiterated his belief that the two uses of arrows should be distinct; he also thinks that using the same symbol as JavaScript has some advantages. D'Aprano, however, is not convinced that following JavaScript's notation is necessarily the right thing for Python, nor does he think there is a need to separate the two uses of arrows. As might be guessed, others disagree; it was, to a certain extent, a bikeshedding opportunity, after all.
For his part, Van Rossum was not really opposed to using the single-line arrow for function definitions if there were no technical barriers to overlapping the two uses. No one seemed to think that allowing type annotations for lambda functions, which are generally quite self-contained, was truly needed. On the other hand, both David Mertz and Ricky Teachey were opposed to adding new syntax to handle lambdas, though Teachey thought it would make more sense if it could be used for both unnamed and named functions:
But if we could expand the proposal to allow both anonymous and named functions, that would seem like a fantastic idea to me.Anonymous function syntax:
(x,y)->x+yNamed function syntax:f(x,y)->x+y
That was something of a step too far for Van Rossum, though. There is already a perfectly good way to create named functions, he said:
Proposals like this always baffle me. Python already has both anonymous and named functions. They are spelled with 'lambda' and 'def', respectively. What good would it do us to create an alternate spelling for 'def'?[...] I can sympathize with trying to get a replacement for lambda, because many other languages have jumped on the arrow bandwagon, and few Python first-time programmers have enough of a CS background to recognize the significance of the word lambda. But named functions? Why??
Greg Ewing hypothesized
that it simply comes from the desire for brevity: "In the situations
where it's appropriate to use a lambda, you want something very
compact, and 'lambda' is a rather long and unwieldy thing to have
stuck in there.
" D'Aprano added
that it may come from mathematical notation for defining functions, which
is not necessarily a good match with Python's def:
So there is definitely some aesthetic advantage to the arrow if you're used to maths notation, and if Python had it, I'd use it.But it doesn't scale up to multi-statement functions, and doesn't bring any new functionality into the language, so I'm not convinced that its worth adding as a mere synonym for def or lambda or both.
While there was some support for the idea, and Sokolovsky is particularly enthusiastic about it, so far there have been no plans mentioned for a Python Enhancement Proposal (PEP). Adopting an arrow syntax for lambda expressions may just be one of those topics that pops up occasionally in Python circles; maybe, like the recurring request for a Python "switch", it will evolve into something that gets added to the language (as with pattern matching). On the other hand, lambda may be one of those corners of the language that is not used frequently enough to be worth changing. Only time will tell.
Index entries for this article | |
---|---|
Python | Enhancements |
Python | Lambda |
(Log in to post comments)
Alternative syntax for Python's lambda
Posted Mar 3, 2021 23:13 UTC (Wed) by NYKevin (subscriber, #129325) [Link]
>>> list(map(f := lambda x: x * 7, [1, 2, 3]))
[7, 14, 21]
>>> f(4)
28
Maybe arrows are better than the lambda keyword, but we've already got a perfectly good way to give names to arbitrary inner expressions. Why invent an alternative syntax just for lambdas? Given how many people vehemently hated the walrus before, during, and after the PEP process, I would naively expect this to go down in flames.
Alternative syntax for Python's lambda
Posted Mar 4, 2021 1:20 UTC (Thu) by rschroev (subscriber, #4164) [Link]
This doesn't change any of the restrictions of lambda: still doesn't allow anything other than one single expression (which I don't think is a problem: if you need anything else, it's easy enough to create a named function). This proposal only changes the syntax a bit. Yet another infraction of the Zen of Python ("There should be one-- and preferably only one --obvious way to do it" in this case), for no real gain. And that change in syntax is contrary to Python's history of favoring clear words over a soup of symbols.
Alternative syntax for Python's lambda
Posted Mar 4, 2021 13:21 UTC (Thu) by t-v (guest, #112111) [Link]
From := to switch to this, I really think that Python is losing slowly using the signature "anyone can read the code to understand what it does" property.
And the "but the beginners" argument looks precisely backward to me. When I am a beginner not knowing lambda and see
def fn(f : Callable) -> int:
...
fn(a -> 2 * a)
what will I ask? "What's with the ascii-art arrow? No the second one?" Ha!
With
def fn(f : Callable) -> int:
...
fn(lambda a: 2 * a)
I can ask "what's with the lambda"?
Using the same thing for two purposes is a bad idea and using line noise instead of words to structure programs does not appear to be making things more beginner-friendly to me. Having these things as words gives us words to talk about them and I don't have to know if it's an arrow or a pointer or a cursor. ("_" is one of these things that is ultimately hard to pronounce, too, and ":="). I think not having ";" much makes Python easier to learn not lest because people don't have to remember what a "semicolon" is.
Alternative syntax for Python's lambda
Posted Mar 5, 2021 12:22 UTC (Fri) by plugwash (subscriber, #29694) [Link]
and you can google "python lambda" and find a bunch of pages describing them.
On the other hand my experience is that search engines mostly ignore symbols, if I google "python {" I just get the python homepage, not a description of python sets and dictionaries.
Alternative syntax for Python's lambda
Posted Mar 6, 2021 7:04 UTC (Sat) by marcH (subscriber, #57642) [Link]
... and for that reason everyone and will keep calling the new arrow notation... "lambda"! So much for "beginner-friendliness".
The beginner-friendly name is "anonymous function" but good luck getting non-beginners used to something that long.
> > > [It's] 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.
Nice one.
Alternative syntax for Python's lambda
Posted Mar 26, 2021 14:29 UTC (Fri) by quantzur (guest, #151322) [Link]
>>> def g(x): return x * 7
...
>>> g(4)
28
>>> g.__name__
'g'
>>> list(map(f := lambda x: x * 7, [1, 2, 3]))
[7, 14, 21]
>>> f(4)
28
>>> f.__name__
'<lambda>'
Alternative syntax for Python's lambda
Posted Mar 4, 2021 5:41 UTC (Thu) by Otus (subscriber, #67685) [Link]
Alternative syntax for Python's lambda
Posted Mar 4, 2021 23:01 UTC (Thu) by da4089 (subscriber, #1195) [Link]
Python 2.7 reached its enormous popularity for being a great balance of complexity and ease of use, which led to PyPI, and it's current status of tool-of-choice for a massive number of programmers. But there were a couple of warts that just annoyed people enough that it was decided to break things, just this once, to fix them. In hindsight, that was probably a mistake, but the language had enough momentum to overcome it, and here we are at 3.10.
Unfortunately, that decade has bred a culture in the core team of believing it's ok to make major changes to the language. The half-baked async/await that dribbled in over the mid 3.x series, pattern matching, and now other frivolous thought bubbles are being taken seriously as potential additions to the language.
There is a fundamental tension to being a language designer/implementer: knowing when to stop. There's a point where you need to start working on a new language, rather than trying to shoehorn your latest novelty into the thing you've already built. It's tough to leave your massive success to one side, and start again at the bottom, but if you don't you end up creating C++, and not C.
I would love to have a Python 4.0 which is a feature freeze of Python 3.x, and the announcement of Snake-0.3b1: like Python but with X and Y and also Z!
(ps. yeah, yeah, get of my lawn, etc)
Alternative syntax for Python's lambda
Posted Mar 5, 2021 7:13 UTC (Fri) by dvdeug (subscriber, #10998) [Link]
There is a fundamental tension to being a language designer/implementer: knowing when to stop. There's a point where you need to start working on a new language, rather than trying to shoehorn your latest novelty into the thing you've already built. It's tough to leave your massive success to one side, and start again at the bottom, but if you don't you end up creating C++, and not C.
And C++ is one of the most successful languages of all time. Fortran 2018 is a horrible mess, but modern Fortrans are still used by people and groups that have been using Fortran for decades. Hyperextended Pascal variants are still used today, whereas Modula-2 and Oberon aren't. Python, Java, C++ and JavaScript are the biggest languages out there and they're extended forms of languages that are at least 25 years old. There's aesthetic reasons to start fresh, but if you want your programming language feature to be used, it's probably going to see much more use if you make it an extension for Python, JavaScript, Java, C++ or C#.
Alternative syntax for Python's lambda
Posted Mar 10, 2021 9:36 UTC (Wed) by anselm (subscriber, #2796) [Link]
And C++ is one of the most successful languages of all time.
C++: The COBOL of the 1980s.
Alternative syntax for Python's lambda
Posted Mar 6, 2021 15:23 UTC (Sat) by Polynka (guest, #129183) [Link]
> I would love to have a Python 4.0 which is a feature freeze of Python 3.x, and the announcement of Snake-0.3b1: like Python but with X and Y and also Z!
Erm…
*looks at ~Perl 6~ Raku*
I don’t think that it’s actually a great idea.
(and I mean its adoption, not the language itself)
Alternative syntax for Python's lambda
Posted Mar 15, 2021 7:37 UTC (Mon) by flussence (subscriber, #85566) [Link]
The most baffling thing to me about the whole epic of Raku isn't how it concluded, but that as recently as last week I still see people who think they're clever for regurgitating hateful Perl 6 FUD from the era when it was still called Perl 6, Slashdot was a relevant tech site, and comparisons to Duke Nukem Forever were still valid. The language is a good tool to write in, but it's accidentally just as valuable for its ability to quickly expose the sort of people with ossified brains and odious worldviews most of us wouldn't want anything to do with.
Alternative syntax for Python's lambda
Posted Mar 10, 2021 1:38 UTC (Wed) by milesrout (subscriber, #126894) [Link]
This is revisionist nonsense. Python 3 development was started long before Python 2.7 existed. PyPI dates back to at least 2003, before Python 2.4 was released, let alone 2.7 (which wasn't released until 2010, seven years later). Meanwhile, Python 3 was first officially released in 2008, but had been floating around as an idea since at least 2006 if not earlier. PEP3000 dates to April 2006, and---as far as I know---was not the first suggestion of a backwards incompatible Python release.
Alternative syntax for Python's lambda
Posted Mar 5, 2021 22:13 UTC (Fri) by flussence (subscriber, #85566) [Link]
If it doesn't, well… people already complain that it's the new Fortran but at this rate it's going to be the new PHP too. Looking forward to that next “fractal of awfulness” blogpost…
Alternative syntax for Python's lambda
Posted Apr 15, 2021 20:20 UTC (Thu) by wtanksleyjr (subscriber, #74601) [Link]
Alternative syntax for Python's lambda
Posted Apr 16, 2021 11:02 UTC (Fri) by hummassa (guest, #307) [Link]
Alternative syntax for Python's lambda
Posted Apr 18, 2021 10:28 UTC (Sun) by flussence (subscriber, #85566) [Link]
It's the easiest way today (and for the past 6 years or so) to run Python 2 and 3 code in an environment with modern quality-of-life features like arrow functions, switch statements and threads. I'm sure there's demand for that somewhere.
Alternative syntax for Python's lambda
Posted Mar 4, 2021 13:51 UTC (Thu) by andrewsh (subscriber, #71043) [Link]
How about making it possible to usedef
without a name?
a = def (x: int, y: bool): return x if z else 0
Alternative syntax for Python's lambda
Posted Mar 5, 2021 1:28 UTC (Fri) by NYKevin (subscriber, #129325) [Link]
1. The anonymous def is an expression which contains one or more statements. Whitespace is normally not significant inside of an expression, but statements have an indentation level, so one of those two rules has to give. At a technical level, this is probably solvable (although the fact that you would be able to nest an anonymous def inside of another anonymous def makes it harder), but at the human level, it makes indentation significantly harder to reason about.
2. The anonymous def is a statement which contains one or more statements. Then you can't nest it inside of arbitrary expressions, and so it is a lot less flexible. You might as well just use a regular def.
3. The anonymous def is an expression which contains exactly one expression. Then it is no more than an alternative spelling of lambda. Why bother?
This has been discussed many times before, and I think it is unlikely that we'll see any sort of "happy middle ground" emerge any time soon.
Alternative syntax for Python's lambda
Posted Mar 10, 2021 2:43 UTC (Wed) by milesrout (subscriber, #126894) [Link]
The first solution is entirely doable. It's not hard to formally specify how indentation and whitespace inside indentation-insensitive expressions would work in a way that is quite intuitive, and where writing something that doesn't parse gives you an *error* instead of failing silently.The way it works currently in Python (or at least you can conceptualise it this way to produce exactly the same result) is that the scanner/lexer parses each token, including whitespace tokens. Then it joins 'continuation lines' joined by backslashes, determines initial whitespace at the beginning of each line and then basically deletes the remaining whitespace, converting it into newline, indent and dedent tokens. Then any indent/dedent/newline tokens inside parens are deleted, so that this continues to work:
x = foo(1, 2)That's seen by the parser as
x = foo ( 1 , 2 ) NEWLINE.not as
x = foo ( 1 , NEWLINE INDENT 2 ) NEWLINE DEDENT.It would be quite simple: mark every newline and indent within a particular depth of bracketing with that depth, and then ignore any indents of greater depth than the current level of bracketing while parsing, and insert virtual dedent tokens when going down levels of nested bracketing.
so that would be
x = foo ( 1 , NEWLINE1 INDENT1 2 DEDENT1 ) NEWLINEso if you had in fact written
x = foo(if True: 2 else: 3)you'd get
x = foo ( if True : NL1 IN1 2 NL1 DE1 else : NL1 ID1 3 NL1 DE1 ) NL1From the perspective of whatever is parsing at the top level, that's:
x = foo ( [arbitrary tokens] ) NLand from the perspective of whatever is parsing inside the parens, that's:
if True : NL IN 2 NL DE else : NL ID 3 NL DEwhich is exactly what you get if you parse that statement at a top level in Python currently (at least conceptually):
if True: # if True : NL 2 # IN 2 NL else: # DE else : NL 3 # IN 3 NL # DEIt's also really easy to implement. I have done so myself as a proof of concept, which I later turned into the parser for a scripting language that is basically Python-with-multi-line-lambdas. It's a few extra lines in the scanner and a few extra lines in the parser. It doesn't slow anything down from a computational complexity perspective. And as a bonus, it gives you a hard error rather than silently-do-the-wrong-thing if you get nested indentation wrong.
I know it's a really popular meme in the Python community that it's OMG2HARD4ME to do multi-line lambdas in a way that gives intuitive, hard-to-get-wrong do-what-I-mean results and is easy and efficient to implement, but as far as I can tell it's just not true.
It would be massively useful. It wouldn't just give multi line lambdas, it would give the ability to nest any expression inside any other expression. All the Python special cases, like generator expressions (just use (for x in y: f(x))
), a if b else c
(just use a proper if statement, although that would be forced to be on at least 2 lines), etc. could be deprecated and phased out eventually.
Of course it will never happen in Python because it's remarkable conservative about syntax that actually matters while wildly liberal with making relatively useless syntax changes like :=
. [You could just write foo((x = 1))
with my suggestion, by the way, which is a far nicer way of doing it than :=
...]
Alternative syntax for Python's lambda
Posted Mar 13, 2021 13:53 UTC (Sat) by HelloWorld (guest, #56129) [Link]
Alternative syntax for Python's lambda
Posted Mar 4, 2021 15:07 UTC (Thu) by LtWorf (subscriber, #124958) [Link]
λ a,b: a+b
Only 1 character instead of 2.
Alternative syntax for Python's lambda
Posted Mar 4, 2021 17:03 UTC (Thu) by aeline (subscriber, #144768) [Link]
Alternative syntax for Python's lambda
Posted Mar 4, 2021 21:05 UTC (Thu) by hasmanean (guest, #145244) [Link]
Alternative syntax for Python's lambda
Posted Mar 10, 2021 2:08 UTC (Wed) by milesrout (subscriber, #126894) [Link]
When symbols are carved into a wax tablet you get what became our UPPERCASE latin alphabet, generally big sharp uncomplicated lines. When the same symbols are drawn onto a parchment or papyrus with a pen, you get the old Roman cursive, which basically became our lowercase.
The letterforms in modern fonts aren't even that similar to the script/cursive forms people use in handwriting today (see 'a' or 'g').
I honestly believe that programmers would use more unicode symbols if the input methods were better. Is that actually a good thing? There are a lot of Unicode confusables after all...
Alternative syntax for Python's lambda
Posted Mar 5, 2021 19:39 UTC (Fri) by cpitrat (subscriber, #116459) [Link]
Alternative syntax for Python's lambda
Posted Mar 5, 2021 21:35 UTC (Fri) by nybble41 (subscriber, #55106) [Link]
<Multi_key> <g> <r> <l> : "λ" U03BB # GREEK SMALL LETTER LAMBDA
Here are the equivalents for lowercase a-z: αβ_δεφγηιθκλμνοπχρστυ_ωξψζ ('c' and 'v' have no corresponding entries and so were replaced with '_').
And the equivalents for uppercase A-Z: ΑΒ_ΔΕΦΓΗΙΘΚΛΜΝΟΠΧΡΣΤΥ_ΩΞΨΖ.
Also many useful symbols: → ⇒ ↑ ↓ × ÷ « » ⋄ ⊛ Ⓧ ¾ ⅞ ☺ € ₡ ¢ ∀ ∃ ±
Unfortunately Windows doesn't have any built-in equivalent to XCompose. I have a few char codes memorized for that, but λ isn't one of them.
To make this work under Linux with X11 you need to create the file ~/.XCompose, set GTK_IM_MODULE=xim and QT_IM_MODULE=xim, and assign some key to the Multi_key function in your keyboard settings. I use the Menu key for Multi_key but you might prefer something else.
[0] https://jessemcdonald.info/gogs/nybble/compose-config/raw...
Alternative syntax for Python's lambda
Posted Mar 5, 2021 21:43 UTC (Fri) by mpr22 (subscriber, #60784) [Link]
Alternative syntax for Python's lambda
Posted Mar 5, 2021 23:58 UTC (Fri) by mbunkus (subscriber, #87248) [Link]
Alternative syntax for Python's lambda
Posted Mar 6, 2021 9:55 UTC (Sat) by LtWorf (subscriber, #124958) [Link]
I don't think the env vars you are exporting are needed. I do not have them.
It used to be that GTK did not support longer sequences than 2 so I had to write them in kwrite and copy paste, but it seems to be working now for a while.
Alternative syntax for Python's lambda
Posted Mar 8, 2021 23:17 UTC (Mon) by nybble41 (subscriber, #55106) [Link]
Yes, that's how I have it configured. In other desktop environments you can use "setxkbmap -option compose:menu" (plus your normal model/layout options) for the same effect.
> I don't think the env vars you are exporting are needed.
If you don't set them then both Gtk and Qt will pick a default input method. If that happens to be XIM then everything will work just fine. If not, the .XCompose file might be ignored; it depends on which input method was chosen. IBUS has some support for reading .XCompose in recent versions. I'm not sure about the others.
Alternative syntax for Python's lambda
Posted Mar 6, 2021 1:49 UTC (Sat) by aeline (subscriber, #144768) [Link]
Alternative syntax for Python's lambda
Posted Mar 6, 2021 1:54 UTC (Sat) by aeline (subscriber, #144768) [Link]
This is really nice for following mathematics/language papers. A snippet from a recent project:
;; Values
(v ::= n
b
∅ ;; Unit
(λ (x : t) e) ;; Value Abstraction
(Λ x e)) ;; Type Abstraction
Alternative syntax for Python's lambda
Posted Mar 10, 2021 3:50 UTC (Wed) by pj (subscriber, #4506) [Link]
U+39b is greek capital lambda
U+3bb is greek small letter lambda
U+1d27 is greek letter small capital lambda
...or one of the other 10ish mathematical lambda characters? (list at https://unicode-table.com/en/search/?q=lambda )
Is there a convention for this? is one more canonical than the others?
Alternative syntax for Python's lambda
Posted Mar 10, 2021 9:12 UTC (Wed) by mpr22 (subscriber, #60784) [Link]
Alternative syntax for Python's lambda
Posted Mar 10, 2021 11:28 UTC (Wed) by fredrik (subscriber, #232) [Link]
In Gnome, and terminals like Alacritty, you use the generic unicode character shortcut, which is Ctrl + Shift + u followed by the unicode code point for lambda which is 03BB, which can be abreviated to 3bb, so basically:Ctrl + Shift + u 3 b b SpaceEasy as pie! 🙂
Alternative syntax for Python's lambda
Posted Mar 22, 2021 16:11 UTC (Mon) by hummassa (guest, #307) [Link]
<Ctrl+k>*l :help digraphs
Alternative syntax for Python's lambda
Posted Mar 4, 2021 20:05 UTC (Thu) by eru (subscriber, #2753) [Link]
Alternative syntax for Python's lambda
Posted Mar 5, 2021 11:53 UTC (Fri) by kpfleming (subscriber, #23250) [Link]
Indeed.int& (*fpi)(int*) = [](auto* a)->auto& { return *a; };Totally readable, only 50% punctuation.
Alternative syntax for Python's lambda
Posted Mar 5, 2021 18:08 UTC (Fri) by eru (subscriber, #2753) [Link]
Alternative syntax for Python's lambda
Posted Mar 22, 2021 16:52 UTC (Mon) by hummassa (guest, #307) [Link]
Whoah? There is nothing but automatic memory management in C++, unless you are usingnew
and delete
, in which case I have a stack of books for you to read before you start over.
Alternative syntax for Python's lambda
Posted Mar 22, 2021 21:31 UTC (Mon) by zlynx (guest, #2285) [Link]
Java's garbage collection has a similar problem here though. Instead of exploding, your "innocent and harmless" capture holds a 300 MB data structure live in RAM.
I've seen C++ lambda captures hold references after a function exits, after a thread exits and even after the program itself exits. Threads continue running even after static object destruction.
Alternative syntax for Python's lambda
Posted Mar 23, 2021 0:27 UTC (Tue) by kpfleming (subscriber, #23250) [Link]
Alternative syntax for Python's lambda
Posted Mar 24, 2021 0:00 UTC (Wed) by nix (subscriber, #2304) [Link]
If there really is a book somewhere discussing how C++ has changed and how typical style has changed, I'd be very interested, because modern C++ has at some point since C++11 dissolved for me from "I can kind of read this if I squint" to "this is a pile of angle brackets and I really have no idea why they are here rather than somewhere else". So I think I have some relearning to do -- but from where?
Alternative syntax for Python's lambda
Posted Mar 5, 2021 19:18 UTC (Fri) by amarao (guest, #87073) [Link]
Rust has second form for closures with {}, but we can ignore those.
Alternative syntax for Python's lambda
Posted Mar 6, 2021 7:03 UTC (Sat) by aeline (subscriber, #144768) [Link]
It feels very visually distinct from tuples, which I think is plus.
Alternative syntax for Python's lambda
Posted Mar 9, 2021 17:07 UTC (Tue) by NYKevin (subscriber, #129325) [Link]
The problem with that is, if you accidentally have any value to its immediate left, then it already parses as a very different expression:
>>> import ast >>> print(ast.dump(ast.parse('z |x, y| x + y - 2', mode='eval'), indent=4)) Expression( body=Tuple( elts=[ BinOp( left=Name(id='z', ctx=Load()), op=BitOr(), right=Name(id='x', ctx=Load())), BinOp( left=Name(id='y', ctx=Load()), op=BitOr(), right=BinOp( left=BinOp( left=Name(id='x', ctx=Load()), op=Add(), right=Name(id='y', ctx=Load())), op=Sub(), right=Constant(value=2)))], ctx=Load()))
(The indent= argument to ast.dump() requires Python 3.9+ for pretty-printing.)
That's not necessarily a complete non-starter, seeing as the lambda syntax probably would not allow you to put a value there, but it would be awkward if a small typo (e.g. omitting a comma) would result in a parse like that. Unfortunately, you can't just say "Well, x and y are non-existent variables, so don't parse it like that." An unrecognized variable is currently interpreted as an uninitialized global; it's assumed that said global will exist by the time the function is actually called (or else it's a runtime error). Python needs to continue to support that use case, or else recursive function calls won't work (functions are "just" variables that point at function objects).
Alternative syntax for Python's lambda
Posted Mar 7, 2021 0:15 UTC (Sun) by marcH (subscriber, #57642) [Link]
Alternative syntax for Python's lambda
Posted Mar 8, 2021 12:16 UTC (Mon) by msuchanek (guest, #120325) [Link]
Somewhat off-topic, but to me, the syntax of map and filter is a bigger issue than lambda. I'd prefer them to be methods rather than functions.
This is pretty hard for me to read:
>>> map(lambda x: x + 1, range(5))
The lambda blends into the arguments and the comma is weak as a visual separator.
This would much easier:
>>> range(5).map(lambda x: x + 1)
Could that be partly to blame for the complaints about the lambda syntax?
Alternative syntax for Python's lambda
Posted Mar 9, 2021 17:32 UTC (Tue) by NYKevin (subscriber, #129325) [Link]
map(lambda x, y: x + y, range(5), reversed(range(5)))
I'm not sure that range(5).map(lambda x, y: x + y, reversed(range(5))) is an improvement. And I'm definitely not writing zip(range(5), reversed(range(5)).starmap(lambda x, y: x + y), because that's just ridiculous.
Alternative syntax for Python's lambda
Posted Mar 11, 2021 8:35 UTC (Thu) by kleptog (subscriber, #1183) [Link]
range(5) |> zip(reversed(range(5)) |> map(lambda x, y: x + y)
Underwater this is converted to:
map(zip(range(5), reversed(range(5)), lambda x, y: x + y)
There is something pleasing about having the operator between the operands, but I don't think Python should go this route. It requires your entire standard library to be designed to make this work well. It's most appropriate for functional languages.
Alternative syntax for Python's lambda
Posted Mar 10, 2021 1:44 UTC (Wed) by milesrout (subscriber, #126894) [Link]
This is not and will never be a good idea. So-called 'UFCS' proposals have failed repeatedly in C++ for good reason, and in Python. Standalone functions are not methods and the method syntax is ugly and misleading. Prioritising one argument over others nearly always makes no sense, and even when it does it's rare that it would be the first argument anyway. Why would it be `foo.map(lambda: ...)` or `foo.map(lambda: ..., bar)` and not `(lambda: ...).map(foo)` or `(lambda: ...).map(foo, bar)`?
I think that it is obvious that we should stick to calling functions as `f(x, y, z)` as we have done in many programming languages for decades and in mathematics for hundreds of years. `x.f(y, z)` makes no sense. `a.plus(b)` is just hideously ugly compared to `plus(a, b)`, and it's totally backwards anyway. If you were going to change to anything it should be `a b plus`, as then at least things would be evaluated entirely left-to-right.
Alternative syntax for Python's lambda
Posted Mar 14, 2021 12:49 UTC (Sun) by cbensf (guest, #120326) [Link]
* map() and filter() should work on any iterable. In Ruby calling them as methods works by all iterables inheriting the Mixin `Enumerable` which keeps growing with time.
But in Python the iteratable/iterator protocols are frozen and extremely narrow. All you need is `__iter__` / `__next__`. This is a feature.
Consider `itertools` module — it extends the set of things you can do with iterators simply by exporting more functions, without adding methods to built-in types. Similarly, countless people have written functions processing iterators, sharing some on PyPI.
[To be fair, *in practice* the Ruby culture of monkey-patching causes surprisingly little problems! So it's more cultural choice than technical argument.]
* There is also a question of symmetry when consuming several iterables, e.g. `zip(foos, bars)` or even the little-known `map(operator.add, foos, bars)`. These would look less pretty as methods on the first sequence...
* There are also various builtins "reducing" an iterable like `sum()`, `all()`, `any()`, `max()` etc. that combine pleasantly with generator expressions. E.g. to test if `n` is composable prime: `any(n % d == 0 for d in range(2, n))`.
In ruby this would be `(2...n).any? { |d| n % d == 0 }` which is a method on Enumerable that takes a block; so in Python this pattern of functions taking an iterator compensates for lack of blocks in some cases...
* A deeper argument IMHO, is that Python has a long tradition of separating the protocol a class has to implement from the public interface one calls.
It does this by operators and global functions, which adds flexibility and helps evolve the language:
- `a < b` operator started out in python 2 calling `a.__cmp__(b)` with fallback to `b.__rcmp__(a)`; later PEP 0207 added `a.__lt__(b)` and `b.__ge__(a)`.
- `bool()` checks `.__nonzero__()_` but falls back to `.__len__()`.
- `iter()` supports objects without `.__iter__` if they implement "sequence" protocol of `.__getitem__` with increasing integers. This allowed the for loop, but also everything else that wants to iterate, to keep working with older classes predating the iterator protocol.
- Even the trivial `.next()` method was wrapped in a builtin function `next()`, which helped abstract the later renaming to `.__next__` (PEP 3114).
Alternative syntax for Python's lambda
Posted Mar 25, 2021 20:06 UTC (Thu) by strombrg (subscriber, #2178) [Link]
I'm opposed to terse-ifying lambda in Python.
Lambda is rarely useful in Python - you're almost always better off using a generator expression, a list comprehension, or something from the operator module.
And lambdas tend to give rise to the software development equivalent of a runon sentence.
Naming a function in those rare cases that you genuinely need something custom really isn't the end of the world, and is more readable anyway.
Alternative syntax for Python's lambda
Posted Mar 31, 2021 20:53 UTC (Wed) by mina86 (guest, #68442) [Link]
> operators used by other languages, such as C#, Java, and JavaScript.
>> 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?
I don’t know about C# but before lambda functions were introduced in
Java, one had to write dozens of lines to get a simple anonymous ‘x+y’
function. This is nothing like Python which has a short lambda
expression.
And as for JavaScript, arrow functions have different semantics than
anonymous functions. The arrow function wasn’t introduced because
‘function’ is such a long word but because programmers couldn’t
comprehend how ‘this’ variable worked. Again, this does not reflect
situation in Python.
Neither comparison is apt.