4 ms·
Python's lack of multi-line anonymous functions is a hindrance to using it as a functional language, IMO.
by heavyset_go 3y ago
Python's lack of multi-line anonymous functions is a hindrance to using it as a functional language, IMO.
- dragonwriter 3y agoMost functional languages don't have statements at all, and Python's anonymous functions can, as most, handle any single expression, regardless of complexity or size. Python having a statement heavy syntax and making complex expressions (while possible) awkward is the problem with its anonymous functions, not the fact that its anonymous functions are limited to a single expression.
- heavyset_go 3y agoDefinitely, I'm looking at this from a superficial level of writing functional programming inspired code in imperative languages. JS makes this a bit more comfortable with its style of anonymous functions.
- nomel 3y agoI take the Beyonce approach to functions: if you like it you should have put a name on it.
- heavyset_go 3y agoI generally agree with this rule, but there are rare occasions where it can get awkward if you're passing functions around, like with callbacks.
- chriswarbo 3y agoMulti-line lambdas are fine: Python will accept newlines in certain parts of an expression, and you can use '\' for others; e.g. f = lambda x: [ x + y for y in range(x) if y % 2 == 0 ] >>> f(5) [5, 7, 9] Lambdas which perform multiple sequential steps are fine, since we can use tuples to evaluate expressions in order; e.g. from sys import stdout g = lambda x: ( stdout.write("Given {0}\n".format(repr(x))), x.append(42), stdout.write("Mutated to {0}\n".format(repr(x))), len(x) )[-1] >>> my_list = [1, 2, 3] >>> new_len = g(my_list) Given [1, 2, 3] Mutated to [1, 2, 3, 42] >>> new_len 4 >>> my_list [1, 2, 3, 42] The problem is that many things in Python require statements, and lambdas cannot contain any; not even one. For example, all of the following are single lines: >>> throw = lambda e: raise e File "<stdin>", line 1 throw = lambda e: raise e ^^^^^ SyntaxError: invalid syntax >>> identity = lambda x: return x File "<stdin>", line 1 identity = lambda x: return x ^^^^^^ SyntaxError: invalid syntax >>> abs = lambda n: -1 * (n if n < 0 else return n) File "<stdin>", line 1 abs = lambda n: -1 * (n if n < 0 else return n) ^^^^^^ SyntaxError: invalid syntax >>> repeat = lambda f, n: for _ in range(n): f() File "<stdin>", line 1 repeat = lambda f, n: for _ in range(n): f() ^^^ SyntaxError: invalid syntax >>> set_key = lambda d, k, v: d[k] = v File "<stdin>", line 1 set_key = lambda d, k, v: d[k] = v ^^^^^^^^^^^^^^^^^^^^ SyntaxError: cannot assign to lambda >>> set_key = lambda d, k, v: (d[k] = v) File "<stdin>", line 1 set_key = lambda d, k, v: (d[k] = v) ^^^^ SyntaxError: cannot assign to subscript here. Maybe you meant '==' instead of '='?
- mixmastamyk 3y agoNeat. I tried it with print(), works fine. Don't need return in a lambda. Assignment now has the walrus. Leaves raise and few other odds and ends. Do believe you've cracked it! Don't think I'll use it much, but you never know... in a pinch.
- chriswarbo 3y agoAh yes, I've been doing this with stdout.write since Python 2; it didn't occur to me that when Python 3 turned print into a function that would make it usable in lambdas! You're right that the walrus makes assignment more usable; we can also call methods like .__setitem__ to get similar effects. Unfortunately the walrus seems to suffer the same broken/ambiguous scoping as assignment statements, e.g. >>> a = 1 >>> b = lambda: (print(a), a := 2) >>> b() Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 1, in <lambda> UnboundLocalError: cannot access local variable 'a' where it is not associated with a value > Don't need return in a lambda `return` is needed for early returns. Notice that my `abs` example is trying to do that with `return n` (to skip the `-1 *` operation, since `n` is non-negative in that case). > Leaves raise and a few other odds and ends Off the top of my head: yield, match, def, import, class, with, for, while, assert, try, except, async, await.
- mixmastamyk 3y agob = lambda: (a := 2, print(a)) Hmm, need to put the assignment before. Can't access nonlocals unless you only read the the var and don't write to it. That's the way functions in python work as well.
- chriswarbo 3y ago> Hmm, need to put the assignment before. No, that would not have the intended behaviour: your `print(a)` is reading a fresh local variable, defined by the `:=` expression (which shadows that from the outer scope), so it will output '2'. The intended behaviour is to print '1' and reassign the outer name; but we can't do that (that's why I chose it as an example!) > Can't access nonlocals unless you only read the the var and don't write to it. That's the way functions in python work as well. Yes, that is precisely what I meant when I said it "suffers the same broken/ambiguous scoping as assignment statements". Python took a haphazard, WorseIsBetter approach to assignment/declaration/scoping. The resulting behaviour is complex, confusing and involves spooky action-at-a-distance (e.g. the meaning of my `print(a)` expression was altered by the presence of an ':=' expression which hadn't been reached yet!). Since this doesn't really affect simple "top to bottom" scripts, it only became an issue once large applications and frameworks started emerging; by that time it was too late to fix, since there was too much Python code in the wild to justify such a large breaking change :(