better lambda support in the future?

D

Dima Dorfman

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)

Sure. You can't change a binding, but you can make it conditional:

let f x =
if x < 0
then let g y = y * -1 in g
else let g y = y in g

Idiomatic OCaml code would use a lambda (fun y -> y * -1), but it
doesn't have to, and that would just confuse the issue.
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...

Both languages compile all three functions (f and the two versions of
g) once and choose which g to return at run-time. You can see this in
Python by examining the code object for f:
(None, 0, <code object g at 1c8120, file "<stdin>", line 3>,
<code object g at 1cd1a0, file "<stdin>", line 6>)

The last two elements are the variants of g. At run-time, one of them
is loaded, made into a real function, and returned. All defs and
lambdas are compiled only once when the module is loaded even if they
depend on the environment or are referenced dynamically.

You can do this even in C (untested):

typedef int fun(int);
int g1(int y) { return y * -1; }
int g2(int y) { return y; }
fun *f(int x)
{
return x < 0 ? g1 : g2;
}

C doesn't have language support for closures, though, so we end up
manually passing around (fun, arg) if we need free variables, but
there's nothing inherently dynamic about higher-order functions.
 
B

Bengt Richter

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.
Looks like your standard pattern could be updated:
... def _(f, name=name):
... dispatch[name] = f
... return f
... return _
... ... def handle_a(): pass
... ... def handle_b(): pass
... ... def handle_c(): pass
... ...
a: <function handle_a at 0x02EE8E9C>
b: <function handle_b at 0x02EE8ED4>
c: <function handle_c at 0x02EE8F0C>

Had to try this experiment:
... def _(f, name=name):
... dispatch[name] = f
... return dispatch
... return _
... ... def dispatch(): return 'dispatched a'
... ... def dispatch(): return 'dispatched b'
... ... def dispatch(): return 'dispatched c'
... ...
a: <function dispatch at 0x02EE8F44>
b: said:
>>> for k in dispatch: print dispatch[k](),
...
dispatched a dispatched c dispatched b
>>> for k in sorted(dispatch): print dispatch[k](),
...
dispatched a dispatched b dispatched c

Hm... this seems like an interesting opening ;-)

Regards,
Bengt Richter
 
T

Terry Reedy

Dima Dorfman said:
Both languages compile all three functions (f and the two versions of
g) once and choose which g to return at run-time.

*If* OCaml or any other 'other' language compiles the two versions of g to
the final and complete functions that get returned (but I don't know if
that is so for OCaml or and other appropriate 'other'), then it does
something different from and less flexible than Python.
You can see this in Python by examining the code object for f:

(None, 0, <code object g at 1c8120, file "<stdin>", line 3>,
<code object g at 1cd1a0, file "<stdin>", line 6>)

It is important that these are code objects, not function objects.
The last two elements are the variants of g. At run-time, one of them
is loaded, made into a real function, and returned. All defs and
lambdas are compiled only once when the module is loaded even if they
depend on the environment or are referenced dynamically.

This is a CPython optimization which, I believe, is not part of the
language def itself -- but any sensible computer implementation should do
something like it.

The final wrapping of the code object by a function object must be done at
runtime because the defaulf arg evaluation and enclosing variable capture
happen on each call of the outer function and because each call therefore
returns a different function object -- though each uses the same code
object (or, in the case discussed, one of the same two code objects).

Terry J. Reedy
 
T

Terry Reedy

Bengt Richter said:
Looks like your standard pattern could be updated:
... def _(f, name=name):
... dispatch[name] = f
... return f
... return _
...... def handle_a(): pass
...... def handle_b(): pass
...... def handle_c(): pass
......
a: <function handle_a at 0x02EE8E9C>
b: <function handle_b at 0x02EE8ED4>
c: <function handle_c at 0x02EE8F0C>

To avoid the redundancy of 'a' and '_a', etc, how about (untested):

def dispvia(f):
dispatch[f.__name__.split('_')[1]] = f
return f

? (Don't have 2.4 loaded yet)

Terry J. Reedy
 
N

Nick Coghlan

Terry said:
To avoid the redundancy of 'a' and '_a', etc, how about (untested):

def dispvia(f):
dispatch[f.__name__.split('_')[1]] = f
return f

A similar idea:

Py> class DispatchTable(dict):
.... def __init__(self, prefix=""):
.... self._prefix = prefix
.... self._ignored = len(prefix)
.... def registerAs(self, name):
.... def _ (f):
.... self[name] = f
.... return f
.... return _
.... def register(self, f):
.... name = f.__name__
.... _ignored = self._ignored
.... if name[:_ignored] == self._prefix:
.... name = name[_ignored:]
.... self[name] = f
.... return f
....
Py> dispatcher = DispatchTable("handle_")
Py> @dispatcher.register
.... def handle_a(): pass
....
Py> @dispatcher.register
.... def b(): pass
....
Py> @dispatcher.registerAs("c")
.... def f(): pass
....
Py> for t in sorted(dispatcher.items()): print '%5s: %r'%t
....
a: <function handle_a at 0x009D8930>
b: <function b at 0x009D85B0>
c: <function f at 0x009D8830>
 
D

Dima Dorfman

*If* OCaml or any other 'other' language compiles the two versions of g to
the final and complete functions that get returned (but I don't know if
that is so for OCaml or and other appropriate 'other'), then it does
something different from and less flexible than Python.

Sorry, I glossed over the details to convey the general idea. In
OCaml, as in Python, the code is compiled once but the closure is made
at run-time.

# f 3 == f 3;;
- : bool = false

where "==" is the physical equality operator like Python's "is".
 
B

Bengt Richter

Bengt Richter said:
Looks like your standard pattern could be updated:
dispatch = {}

def dispvia(name):
... def _(f, name=name):
... dispatch[name] = f
... return f
... return _
...
@dispvia('a')
... def handle_a(): pass
...
@dispvia('b')
... def handle_b(): pass
...
@dispvia('c')
... def handle_c(): pass
...
for t in sorted(dispatch.items()): print '%5s: %r'%t
...
a: <function handle_a at 0x02EE8E9C>
b: <function handle_b at 0x02EE8ED4>
c: <function handle_c at 0x02EE8F0C>

To avoid the redundancy of 'a' and '_a', etc, how about (untested):

def dispvia(f):
dispatch[f.__name__.split('_')[1]] = f
return f

? (Don't have 2.4 loaded yet)

That should work. Didn't want to retype ;-) I just wanted to get
to the experiment following -- did you notice that it takes the assignment
name from each "def dispatch ...", but it is actually re-assigning the returned dispatch
*dict* as the value, not a modified function? So no function was bound to any local name at
any time. Kind of faking the lambda thing, and allowing non-identifier keys if desired. E.g.,
... def _(f, name=name):
... f.__name__ = repr(repr(name))
... dispatch[name] = f
... return dispatch
... return _
... ... @dispvia(k)
... def dispatch(key=k): return key
... ...
0: <function '0' at 0x02EE8DBC>
1: said:
>>> for t in sorted(dispatch.items()): print '%r() => %r' % (t[1], t[1]())
...
<function '0' at 0x02EE8DBC>() => 0
<function '1' at 0x02EE8DF4>() => 1
<function '2' at 0x02EE8E2C>() => 2

Sort of the effect of
...
0:<function <lambda> at 0x02EE8FB4>
1:<function <lambda> at 0x02EF402C>
2:<function <lambda> at 0x02EF409C>

Oops, well it's not so pretty if you want to rename the lambdas in the same expression:
...
0:<function '0' at 0x02EE8FB4>
1: said:
>>> for t in sorted(dispatch.items()): print '%r() => %r' % (t[1], t[1]())
...
<function '0' at 0x02EE8DBC>() => 0
<function '1' at 0x02EE8DF4>() => 1
<function '2' at 0x02EE8E2C>() => 2

;-/

Regards,
Bengt Richter
 
T

Terry Reedy

Bengt Richter said:
To avoid the redundancy of 'a' and '_a', etc, how about (untested):

def dispvia(f):
dispatch[f.__name__.split('_')[1]] = f
return f
That should work. Didn't want to retype ;-) I just wanted to get
to the experiment following -- did you notice that it takes the
assignment
name from each "def dispatch ...", but it is actually re-assigning the
returned dispatch
*dict* as the value, not a modified function?

Yes, I noticed that your second version of dispvia, which I snipped,
returned dispatch instead of the nested function named _. But I did not
quite think thru the import of so doing.

I think one or more of these recipies might at least be worthy of the
cookbook site so they can be easily referenced in response to future
postings.

Terry J. Reedy
 
D

Doug Holton

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?

See boo and its support for closures: http://boo.codehaus.org/
http://boo.codehaus.org/Closures

It works with "def" or "do", or single-line closures use {}.

x = def:
print "hello"

A closure with parameters:

c = def(x1 as int, x2 as string):
print x1, x2

Single line closures use {}

c = {print("hello")}

Single line with parameters

c = {item as string | print(item)}


#Passing closures to a method as a parameter:

def mymethod(c as callable):
c()

x = mymethod( {print("hello")} )

#passing a multi-line closure as a parameter:

x = mymethod() do():
print "hello"

#Adding a closure to an event handler:

button.Click += def ():
print("${button} was clicked!")
 
B

Bengt Richter

Bengt Richter said:
To avoid the redundancy of 'a' and '_a', etc, how about (untested):

def dispvia(f):
dispatch[f.__name__.split('_')[1]] = f
return f
That should work. Didn't want to retype ;-) I just wanted to get
to the experiment following -- did you notice that it takes the
assignment
name from each "def dispatch ...", but it is actually re-assigning the
returned dispatch
*dict* as the value, not a modified function?

Yes, I noticed that your second version of dispvia, which I snipped,
returned dispatch instead of the nested function named _. But I did not
That's actually not the right "instead" ;-) I.e., the function _ returns
dispatch instead of the function passed to _it_ for deco-modification.
quite think thru the import of so doing.

I think one or more of these recipies might at least be worthy of the
cookbook site so they can be easily referenced in response to future
postings.
It is a little sneaky though, so it might not be prudent to promote
without a little more experimentation? I just like to explore ;-)

Regards,
Bengt Richter
 
N

Nick Coghlan

Bengt said:
It is a little sneaky though, so it might not be prudent to promote
without a little more experimentation? I just like to explore ;-)

I don't think even the py-dev discussions of this settled on whether such tricks
were "very cool" or "downright evil".

They're probably less evil than sys._getframe hacks, though :)

Cheers,
Nick.
 
A

Antoon Pardon

Op 2004-12-17 said:
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?

Do you name every object, number, string ... before you use it.
If not it seems you don't object to anonymity.

And yes it sometimes is hard. Of course you can just name it f1, f2 etc,
but that is no improvement over anonymity and sometimes the best you
can do is describe what the function does, but the code does that
better.
 

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

Forum statistics

Threads
473,767
Messages
2,569,572
Members
45,045
Latest member
DRCM

Latest Threads

Top