better lambda support in the future?

J

Jason Zheng

I'm wondering why python still has limited lambda support. What's
stopping the developers of python to support more lisp-like lambda function?
 
S

Steven Bethard

Jason said:
I'm wondering why python still has limited lambda support. What's
stopping the developers of python to support more lisp-like lambda
function?

This comes up every few weeks on the list. If you haven't already,
check the archives in Google for 'anonymous def' or 'anonymous
function'. The usual response to this question is something along the
lines of "if it's good enough to create a function for, it's good enough
to name".

One of the other big reasons for this type of proposal never making it
far is that, so far, no one has found a syntax that everyone (or even
most people) like. You end up with things like:

x = func or lambda x, y:
# body of lambda func
# indented here

or

x = func or lambda x, y:
# body of lambda func
# indented here

or

x = func or lambda x, y {
# body of lamda func indented
# however you want...
}

or any thousand other varieties.

Even if you could settle the syntax issue, once you've decided that you
really do need a true block in an anonymous function, you're not really
saving much space by not declaring it:

def f(*args):
# body line 1
# body line 2
# ...
# body line N
x = func or f

v.s.

x = func or lambda *args:
# body line 1
# body line 2
# ...
# body line N

so, you save a single line, which is only 1 Nth of the size of your
function (where N is the number of lines in your function body). For a
single or double line function, these savings may be more substantial,
but chances are if your function is only one or two lines, it can be
written as an expression anyway (e.g. using LCs or GEs)...


Do check the archives -- there are a lot of discussions on this topic,
but hopefully the brief commentary above will give you something of an
overview.

Steve
 
F

Fredrik Lundh

Steven said:
Even if you could settle the syntax issue, once you've decided that you really do need a true
block in an anonymous function, you're not really saving much space by not declaring it:

def f(*args):
# body line 1
# body line 2
# ...
# body line N
x = func or f

v.s.

x = func or lambda *args:
# body line 1
# body line 2
# ...
# body line N

you meant:

def x(*args):
# body line 1
# body line 2
# ...
# body line N

v.s.

x = func or lambda *args:
# body line 1
# body line 2
# ...
# body line N

right?

</F>
 
J

Jason Zheng

Steven said:
This comes up every few weeks on the list. If you haven't already,
check the archives in Google for 'anonymous def' or 'anonymous
function'. The usual response to this question is something along the
lines of "if it's good enough to create a function for, it's good enough
to name".

The true beauty of lambda function is not the convenience of creating
functions without naming them. Lambda constructs truly enables
higher-order function. For example, I can create a function A that
returns a function B that does something interesting according to the
arguments that I pass to function A.
 
S

Steven Bethard

Fredrik said:
Steven Bethard wrote:




you meant:

def x(*args):
# body line 1
# body line 2
# ...
# body line N

v.s.

x = func or lambda *args:
# body line 1
# body line 2
# ...
# body line N

right?

You're welcome to name the function whatever you want -- notice in my
example that the function is used in the statement:

x = func or f

If you'd prefer the statement to read:

x = func or x

that's also fine. Depends on what exactly 'x' is, and whether or not it
really makes sense for the function I called 'f' to have the same name
as the variable called 'x'. It certainly may, but since I wasn't giving
real code, I didn't want to commit to that.

Perhaps a better example would have been something along the lines of:

dict(a=lambda *args:
# body 1
,
b=lambda *args:
# body 2
,
c=lambda *args:
# body 3
)(values)

v.s.

def a_func(*args):
# body 1
def b_func(*args):
# body 2
def c_func(*args):
# body 3
dict(a=a_func, b=b_func, c=c_func)(values)

where it's clear that I'm trying to use lambdas where expressions are
required.

I assume that the point you were trying to make is that:

def f(*args):
return expr

is equivalent to

f = lambda *args: expr

?

Steve
 
M

Michael DeHaan

True enough, but suppose you want a hash of anonymous functions as
opposed to just a lexical? This is where lambas are nice to have.
Totally agreed about a small use here and there, but they do have some
use in dispatch tables, as they are a lot easier to read sometimes
than very long case statements. Of course, this would require
multi-line lambdas to exist...

--Michael
 
F

Fredrik Lundh

Steven said:
You're welcome to name the function whatever you want -- notice in my example that the function is
used in the statement:

x = func or f

If you'd prefer the statement to read:

x = func or x

that's also fine. Depends on what exactly 'x' is, and whether or not it really makes sense for
the function I called 'f' to have the same name as the variable called 'x'. It certainly may, but
since I wasn't giving real code, I didn't want to commit to that.

if you write "def f", "f" is a variable, just like "x". "def" is an assignment
statement.

I'm not sure what "func" is supposed to be in your examples...
I assume that the point you were trying to make is that:

def f(*args):
return expr

is equivalent to

f = lambda *args: expr

?
.... return 1+2
.... 2 0 LOAD_CONST 1 (1)
3 LOAD_CONST 2 (2)
6 BINARY_ADD
7 RETURN_VALUE 1 0 LOAD_CONST 1 (1)
3 LOAD_CONST 2 (2)
6 BINARY_ADD
7 RETURN_VALUE
['__call__', '__class__', '__delattr__', '__dict__', '__doc__', '__get__', '__ge
tattribute__', '__hash__', '__init__', '__module__', '__name__', '__new__', '__r
educe__', '__reduce_ex__', '__repr__', '__setattr__', '__str__', 'func_closure',
'func_code', 'func_defaults', 'func_dict', 'func_doc', 'func_globals', 'func_na
me']['__call__', '__class__', '__delattr__', '__dict__', '__doc__', '__get__', '__ge
tattribute__', '__hash__', '__init__', '__module__', '__name__', '__new__', '__r
educe__', '__reduce_ex__', '__repr__', '__setattr__', '__str__', 'func_closure',
'func_code', 'func_defaults', 'func_dict', 'func_doc', 'func_globals', 'func_na
me']
'<lambda>'

</F>
 
S

Steven Bethard

Fredrik said:
I'm not sure what "func" is supposed to be in your examples...

Just an extra variable used to make sure that the lambda was being used
in a context (i.e. in an expression) where a simple def wouldn't
suffice. If the example is confusing, consider the dict example
instead. It makes it clearer that the lambdas are being used in places
where an expression is required.

Steve
 
S

Steven Bethard

Michael said:
True enough, but suppose you want a hash of anonymous functions as
opposed to just a lexical?

I've seen at least one reasonable example of this kind of thing:

http://mail.python.org/pipermail/python-list/2004-October/245432.html

Though I haven't yet seen an example that actually required lambdas with
blocks...
Totally agreed about a small use here and there, but they do have some
use in dispatch tables, as they are a lot easier to read sometimes
than very long case statements. Of course, this would require
multi-line lambdas to exist...

Certainly in the example above, I'd be willing to agree that the lambdas
are at least as readable as a buch of def's above would have been. I'm
not sure if multi-line lambdas would be as readable though... It all
depends on what syntax you write them in -- you can see the struggle I
went through in my other message... Where do I put the commas in a
dict? Can't be at the end of the lambda or they turn the last
expression into a tuple... I resorted to putting them on a separate
line, but of course there are other solutions.


If you have a good example of where you'd like to use multi-line
lambdas, in, say, a dispatch table, I'd like to take a look at how you'd
like to write them. I'm not yet convinced that there really is a
readable way to write such things...

Steve
 
F

Fredrik Lundh

Michael said:
True enough, but suppose you want a hash of anonymous functions as
opposed to just a lexical? This is where lambas are nice to have.
Totally agreed about a small use here and there, but they do have some
use in dispatch tables, as they are a lot easier to read sometimes
than very long case statements.

standard pattern:

dispatch = {}

def handle_a(...):
...
dispatch["a"] = handle_a

def handle_b(...):
...
dispatch["b"] = handle_b

def handle_c(...):
...
dispatch["c"] = handle_c

if you cannot think of a suitable name for a given case, you can
name them all "case". for further encapsulation, you can put this
in a class definition; dispatch will then become a dictionary con-
taining unbound methods. if the case names all happen to be valid
Python literals, you can get rid of the dispatch dictionary, and use
getattr(self, "handle_" + case) to locate the right bound method (or
if speed is important, use dir() to preload a dispatch dictionary with
handlers). etc.

</F>
 
S

Steven Bethard

Jason said:
The true beauty of lambda function is not the convenience of creating
functions without naming them. Lambda constructs truly enables
higher-order function. For example, I can create a function A that
returns a function B that does something interesting according to the
arguments that I pass to function A.

Like this?

def A(*args, **kwds):
def B():
print args, kwds
return B

But you don't need lambdas to do this. In fact, even in your email,
you'll note that you referred to your two functions by name. If you're
naming functions, why not use a def statement?

Steve
 
F

Fredrik Lundh

Steven said:
I've seen at least one reasonable example of this kind of thing:

http://mail.python.org/pipermail/python-list/2004-October/245432.html

the code he's referring to doesn't seem to use that construct anymore, so
it's not obvious what "dejavu.icontains" etc really is, but assuming they're
strings, the following is a reasonable lambda-free alternative:

class xforms:
def icontains(self, x, y): return x + " Like '%" + y[1:-1] + "%'"
def icontainedby(self, x, y):
# icontainedby body goes here instead of in a separate function
def istartswith(self, x, y): return x + " Like '" + y[1:-1] + "%'"
def iendswith(self, x, y): return x + " Like '%" + y[1:-1] + "'"
def ieq(self, x, y): return x + " = " + y
def now(self): return "Now()"
def today(self): return "DateValue(Now())",
def year(self, x): return "Year(" + x + ")"
def dispatch(self, tag, *args):
return getattr(self, tag)(*args)

here's another "reasonable example", btw:

http://groups-beta.google.com/group/comp.lang.python/msg/11462b89a490a6ac

this too could be rewritten to use a class (combined with re.sub and
a callback, most likely).

</F>
 
M

Michael Hoffman

Jason said:
The true beauty of lambda function is not the convenience of creating
functions without naming them. Lambda constructs truly enables
higher-order function. For example, I can create a function A that
returns a function B that does something interesting according to the
arguments that I pass to function A.

How does that differ from this?
.... if x:
.... def B(): return "True"
.... else:
.... def B(): return "False"
.... return B
....'False'
 
S

Steven Bethard

Fredrik said:
Steven said:
I've seen at least one reasonable example of this kind of thing:

http://mail.python.org/pipermail/python-list/2004-October/245432.html

the code he's referring to doesn't seem to use that construct anymore, so
it's not obvious what "dejavu.icontains" etc really is, but assuming they're
strings, the following is a reasonable lambda-free alternative:

class xforms:
def icontains(self, x, y): return x + " Like '%" + y[1:-1] + "%'"
def icontainedby(self, x, y):
# icontainedby body goes here instead of in a separate function
def istartswith(self, x, y): return x + " Like '" + y[1:-1] + "%'"
def iendswith(self, x, y): return x + " Like '%" + y[1:-1] + "'"
def ieq(self, x, y): return x + " = " + y
def now(self): return "Now()"
def today(self): return "DateValue(Now())",
def year(self, x): return "Year(" + x + ")"
def dispatch(self, tag, *args):
return getattr(self, tag)(*args)

This doesn't work if the strings aren't valid Python identifiers (e.g.
"!CONTAINS!"). On the other hand, if they are (and you can be
guaranteed that they will continue to be), then your solution above is
nice, though if you want to fully reproduce the behavior, you probably
also want the method

def __getitem__(self, item):
return getattr(self, item)

Steve
 
T

Terry Reedy

They already have: given the fundamental syntax difference between all
expressions and expressions within statements, def statements are at least
the equivalent of lisp lambdas + name binding. When you get an exception
traceback, a unique name is more helpful than the pseudoname <lambda>.
Isolating the definition of a function in a separate statement also makes
it possible to unittest the function.

What puzzles me is 1) why some people apparently think anonymity is good --
is it really that hard to name non-trivial functions? and 2) why some
people are so quick to recommend changes to Python before they understand
what they can already do (wth def statements, in this case).
The true beauty of lambda function is not the convenience of creating
functions without naming them. Lambda constructs truly enables
higher-order function.

And so do Python def statements coupled with Python design principles. In
Python at least, the beauty of first-class functions has nothing to do with
'lambda'.
For example, I can create a function A that returns a function B that
does something interesting according to the arguments that I pass to
function A.

Golly gee. Pythoneers have done this with def for at least a decade, if
not from the very beginning.

Terry J. Reedy
 
J

Jeff Shannon

Steven said:
But you don't need lambdas to do this. In fact, even in your email,
you'll note that you referred to your two functions by name. If
you're naming functions, why not use a def statement?


It occurs to me that, in a statically compiled language, function
definitions all happen before the program starts, and thus that
definition can't be affected by other variables (i.e. an outer
function's parameters). In such statically compiled language, a lambda
would be very useful simply because it's a *dynamic* function. Of
course, in Python *all* functions are created dynamically, therefore
(unlike most other languages) the majority of the benefits of lambdas
already apply to standard Python functions.

In the couple of years that I've been puzzling over why some people were
so fixated upon lambdas as being essential, this hasn't occurred to me
before. They really provide scant benefit in Python (which is why I was
puzzled by the devotion to them), but they *do* provide a large benefit
in other languages. It is, however, quite easy to miss that this
relative weakness of Python lambdas is a direct consequence of the fact
that a function def is an executable statement rather than a
compilation-time declaration.

Jeff Shannon
Technician/Programmer
Credit International
 
S

Steven Bethard

Jeff said:
It occurs to me that, in a statically compiled language, function
definitions all happen before the program starts, and thus that
definition can't be affected by other variables (i.e. an outer
function's parameters).

I think you might be confusing static compilation in a language with
lack of first-class functions in a language. OCaml is compiled, but
functions are first class objects, and nested scopes are accessible:

# let f x =
let g y =
x + y
in
g;;
val f : int -> int -> int = <fun>
# f(1);;
- : int -> int = <fun>
# f(1)(2);;
- : int = 3

Note that the type of f is a function that takes an int and returns a
function that takes an int and returns an int. OCaml handles nested
scopes appropriately, and successfully compiles the function f (and
infers the appropriate types). So the issue is not static compilation,
but functions as first class objects.

Of course, many statically compiled languages, e.g. C, C++, Java, do not
provide functions as first class objects, so the confusion is not
unnatural...

Steve
 
J

Jeff Shannon

Steven said:
I think you might be confusing static compilation in a language with
lack of first-class functions in a language.


Hm, possibly. I must confess that my direct knowledge is limited to a
fairly narrow set of languages, and that C and C++ are the only
statically-compiled languages I've used. Still, I'm not sure that it's
just a matter of functions as first-class objects. Would OCaml (or some
other static language) have something that's equivalent to this?

def f(x):
if x < 0:
def g(y):
return y * -1
else:
def g(y):
return y
return g

foo = f(1)

Here, nested scopes are not enough. Only one of these functions is
created, and which one that is depends on the run-time value of the
function parameter. A compiler couldn't know this ahead of time. I
suppose it might be able to do something by compiling both of them,
(though I'm not sure how it'd track two different functions with the
same name in the same namespace...) but that seems a bit questionable to
me...

Jeff Shannon
Technician/Programmer
Credit International
 
M

Mike Meyer

Jeff Shannon said:
Steven Bethard wrote:
Hm, possibly. I must confess that my direct knowledge is limited to a
fairly narrow set of languages, and that C and C++ are the only
statically-compiled languages I've used. Still, I'm not sure that
it's just a matter of functions as first-class objects. Would OCaml
(or some other static language) have something that's equivalent to
this?

def f(x):
if x < 0:
def g(y):
return y * -1
else:
def g(y):
return y
return g

foo = f(1)

This is really no different than:

def f(x):
if x < 0:
g = -y
else:
g = y
return g

The only difference is that you're binding the variable g to a y type
instead of a function type. That's what "first class functions"
means. You can treat functions like any other object, assign them to
variables, pass them as parameters, and so on.

<mike
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,051
Latest member
CarleyMcCr

Latest Threads

Top