A replacement for lambda

P

Paul Rubin

Seth Nielson said:
Any replacement must support the following: *delayed evaluation*.

I need a convenient (def is not always convenient) way of saying,
"don't do this now". That is why I use lambda.

How's this: f{args} (curly braces instead of parens) is the same as
f(lambda: args).

Examples:

launch_thread{targetfunc(a,b,c)}

b = Button{callback=pressed()} # Button remembers callback()

def ternary(cond, x, y):
if cond(): return x()
else: return y()

sign_of_a = ternary{a < 0, -1, 1}


etc.
 
P

Paul Rubin

Seth Nielson said:
Any replacement must support the following: *delayed evaluation*.

I need a convenient (def is not always convenient) way of saying,
"don't do this now". That is why I use lambda.

How's this: f{args} (curly braces instead of parens) is the same as
f(lambda: args).

Examples:

launch_thread{targetfunc(a,b,c)}

b = Button{callback=pressed()} # Button remembers callback()

def ternary(cond, x, y):
if cond(): return x()
else: return y()

sign_of_a = ternary{a < 0, -1, 1}


etc.
 
B

Bengt Richter

I know, lambda bashing (and defending) in the group is one of the most
popular ways to avoid writing code. However, while staring at some Oz
code, I noticed a feature that would seem to make both groups happy -
if we can figure out how to avoid the ugly syntax.

This proposal does away with the well-known/obscure "lambda"
keyword. It gives those who want a more functional lambda what they
want. It doesn't add any new keywords. It doesn't add any new magic
characters, though it does add meaning to an existing one. That could
be replaced by a new magic token, or adding magic meaning to a
non-magic token. It breaks no old code either way.

I haven't really worked out all the implications; I just wanted to
throw it out and see what everyone else thought about it. As a
result, the code examples tend to be ugly.

As previously hinted, this feature is lifted from Oz.

Currently, class and functions definitions consist of a keyword -
either "class" or "def" - followed by a name, a header, then code. The
code is compiled into an object, and the name is bound to that object.

The proposal is to allow name to be a non-name (or rare name)
token. In this case, the code is compiled and the resulting object is
used as the value of the class/def expression.

My choice for the non-name token is "@". It's already got magic
powers, so we'll give it more rather than introducing another token
with magic powers, as the lesser of two evils.

Rewriting a canonical abuse of lambda in this idiom gives:

myfunc = def @(*args):
return sum(x + 1 for x in args)

If you remove the '@' -- which is not really needed -- you have exactly my (at least
I think it was mine -- the variation are, in any case ;-) old anonymous def proposal.

So good luck in getting any more favorable attention than I did ;-)
I've also proposed named and anonymous callable local blocks for
the other variations of removing 'def' and/or the binding name from
normal def syntax. E.g.,

def my_func(*args): # normal def
return sum(x + 1 for x in args)

my_func = def(*args): # anonymous def expression
return sum(x + 1 for x in args)

my_local_callable_block(*args): # named local callable block
nargs = len(args) # binds nargs as if this suite were e.g. an "if" suite.
return sum(x + 1 for x in args)

my_local_callable_block = (*args): # local callable block expression
nargs = len(args) # binds nargs as if this suite were e.g. an "if" suite.
return sum(x + 1 for x in args)

The local callable blocks can be made accessible via a dict or list or whatever and called like

lcb_dict[key](args)

to have the bindings occur in the scope of the block definition. This avoids the problem of
the typical case dispatch of function calls via a dict, where the function has its own temporary
local namespace and binding in the calling namespace is kludgey.


In other words, this is identical to:

def myfunc(*args):
return sum(x + 1 for x in args)

We can write the same loop with logging information as:

sum(def @(arg):
print "Bumping", arg
return arg + 1
(x) # '(' at the same indent level as def, to end the definition
for x in stuff)

You are almost quoting me in previous posts (protesting that the indentation "problem" is no big deal ;-)
A more useful example is the ever-popular property creation without
cluttering the class namespace:

class Spam(object):
myprop = property(fget = def @(self):
return self._properties['myprop']
,
fset = def @(self, value):
self._properties['myprop'] = value
,
fdel = def @(self)
del self._properties['myprop']
,
doc = "Just an example")
Again, the '@' is not necessary ;-)
This looks like the abuse of lambda case, but these aren't
assignments, they're keyword arguments. You could leave off the
keywords, but it's not noticably prettier. fget can be done with a
lambda, but the the others can't.
Well, they can, but it's not pretty ;-)
Giving clases the same functionality seems to be the reasonable thing
to do. It's symmetric. And if anonymous function objects are good,
then anonymous class objects ought to be good as well.
I agree.

Regards,
Bengt Richter
 
B

Bengt Richter

I know, lambda bashing (and defending) in the group is one of the most
popular ways to avoid writing code. However, while staring at some Oz
code, I noticed a feature that would seem to make both groups happy -
if we can figure out how to avoid the ugly syntax.

This proposal does away with the well-known/obscure "lambda"
keyword. It gives those who want a more functional lambda what they
want. It doesn't add any new keywords. It doesn't add any new magic
characters, though it does add meaning to an existing one. That could
be replaced by a new magic token, or adding magic meaning to a
non-magic token. It breaks no old code either way.

I haven't really worked out all the implications; I just wanted to
throw it out and see what everyone else thought about it. As a
result, the code examples tend to be ugly.

As previously hinted, this feature is lifted from Oz.

try

http://groups-beta.google.com/groups?as_q=anonymous+def&as_ugroup=comp.lang.python

for much discussion of this ;-)

Regards,
Bengt Richter
 
B

Bengt Richter

I know, lambda bashing (and defending) in the group is one of the most
popular ways to avoid writing code. However, while staring at some Oz
code, I noticed a feature that would seem to make both groups happy -
if we can figure out how to avoid the ugly syntax.

This proposal does away with the well-known/obscure "lambda"
keyword. It gives those who want a more functional lambda what they
want. It doesn't add any new keywords. It doesn't add any new magic
characters, though it does add meaning to an existing one. That could
be replaced by a new magic token, or adding magic meaning to a
non-magic token. It breaks no old code either way.

I haven't really worked out all the implications; I just wanted to
throw it out and see what everyone else thought about it. As a
result, the code examples tend to be ugly.

As previously hinted, this feature is lifted from Oz.

try

http://groups-beta.google.com/groups?as_q=anonymous+def&as_ugroup=comp.lang.python

for much discussion of this ;-)

Regards,
Bengt Richter
 
P

Peter Hansen

Paul said:
How's this: f{args} (curly braces instead of parens) is the same as
f(lambda: args).

Examples:

launch_thread{targetfunc(a,b,c)}
b = Button{callback=pressed()} # Button remembers callback()
sign_of_a = ternary{a < 0, -1, 1}

I'd consider this an interesting idea if it weren't for the fact that
(at least with the fonts I generally use) I can barely make out the
difference between the {} and the () above.

-Peter
 
P

Paul Rubin

Peter Hansen said:
I'd consider this an interesting idea if it weren't for the fact that
(at least with the fonts I generally use) I can barely make out the
difference between the {} and the () above.

Ok, how about an escaped paren:
sign_of_a = ternary\(a < 0, -1, 1)
 
J

Jeff Epler

C++ solves this exact problem quite reasonably by having a greedy
tokenizer. Thus, that would always be a left shift operator. To make it
less than and a function, insert a space:
<x**2 with(x)>< <x**3 with(x)>

Incidentally, I read in an article by Bjarne Stroustrup[1] that "C++0x" will parse
vector<vector<double>> v;
just like today's compilers parse
vector<vector<double> > v;

Another of the changes he discusses, letting 'auto i = ...' create i
with the type of the expression '...', will certainly be an improvement.
Even better if the keyword 'auto' could be made optional! (Of course,
this is another break with C, where the declaration
auto i;
makes 'i' an int)

And what's this got to do with Python? I dunno. Sorry.

Jeff
[1] http://www.informit.com/content/images/art_stroustrup_2005/elementLinks/rules.pdf

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.6 (GNU/Linux)

iD8DBQFC7ABaJd01MZaTXX0RArfAAJ9dpNfnpvVt/iOctmMdwgmpoTQLHgCdFttG
AI5ZtzcaYrntXHy9YRfVqX4=
=td3E
-----END PGP SIGNATURE-----
 
C

Christopher Subich

Paul said:
But how does that let you get more than one expression into the
anonymous function?

It doesn't. Functionally, it's a direct replacement of lambda as-is.
 
C

Christopher Subich

Scott said:
What kind of shenanigans must a parser go through to translate:
<x**2 with(x)><<x**3 with(x)>

this is the comparison of two functions, but it looks like a left-
shift on a function until the second with is encountered. Then
you need to backtrack to the shift and convert it to a pair of
less-thans before you can successfully translate it.

I hadn't thought of that, but after much diving into the Python grammar,
the grammar would still work with a greedy tokenizer if "<<" (and also
">>", for identical reasons) were replaced in 'shift_expr" with "<" "<"
and ">" ">".

That, of course, introduces some weirdness of '''a = 5 < < 3''' being
valid. I'm not sure whether that is a wart big enough to justify a
special-case rule regarding '>>' and '<<' tokens. We do allow
'def f () :'
as-is, so I'm not sure this is too big of a problem.
 
C

Christopher Subich

Paolino said:
why (x**2 with(x))<(x**3 with(x)) is not taken in consideration?

Looks too much like a generator expression for my taste. Also, <expr
...> syntax could be used with 'for' instead of 'with' if PEP343 poses a
problem, whereas (expr for params) is identically a generator expression.
If 'with' must be there (and substitue 'lambda:') then at least the
syntax is clear.IMO Ruby syntax is also clear.

I haven't used Ruby myself, but as I understand it that language allows
for full anonymous blocks. Python probably doesn't want to do that.
 
C

Christopher Subich

Paddy said:
I do prefer my parameter list to come before the expression. It would
remain consistant with simple function definitions.

Stylistic choice; I can appreciate your sentiment, but remember that
this isn't exactly a function definition. It's a form of 'delayed
expression.' Also, <... with ...> is nearly identical (identical if you
replace 'with' with 'for') to existing list and generator
comprehensions, so we'd get to stretch that idiom.
 
M

Mike Meyer

B

Bengt Richter

Well, that pretty much kills that. I knew there had been a lot of
Well, why consider it killed? Maybe your weight could tilt the balance ;-)
I still like the anonymous def.
discussion about anonymous functions, anonymous blocks, and of course
various lambda replacements. But I didn't realize almost exactly this
proposal had been discussed before. Shouldn't surprise me, though.

Thanks to everyone who took the time to read and respond.
Sometimes ideas have to sit in the mulch for a while before it's their season to bloom ;-)

Regards,
Bengt Richter
 

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,780
Messages
2,569,611
Members
45,273
Latest member
DamonShoem

Latest Threads

Top