map/filter/reduce/lambda opinions and background unscientificmini-survey

R

Ron Adam

Stian said:
So you could do lot's of funny things like:

def my_fun(extra_args=None):
if not extraargs:
print "Behave normally"
extra_args = 1337

if extraargs:
asdkjaskdj
..
if extra_args:
kajsdkasjd

Yes, returning None from an undefined name is DOA.

In the above case you would get an error by the way.

"if extraargs:" would evaluate to "if None:", which would evaluate to
"if:" which would give you an error.

This is the only "good" case I could find, but opening for a lots of
errors when you get used to that kind of coding:

It would need to be.. while not (something==None): and the compiler
would need to handle it as a special case. But this one could still
work without allowing something=undefined to be valid.
while not finished:
foo()
finished = calculate_something()

(..)
(..) # Added another loop
while not finished:
bar()
finished = other_calculation()

Guess the amount of fun trying to find out the different errors that
could occur when bar() does not run as it should because the previous
"finished" variable changes the logic.

It's not really differnt than any other value test we currently use.

notfinished = True
while notfinished:
notfinished = (condition)

# Need to set notfinished back to True here.
while notfinished:
Now this is a question from newcomers on #python each day.. "How do I
check if a variable is set?".

Why do you want to check if a variable is set at all? If you have so
many places the variable could or could not be set, your program design
is basically flawed and must be refactored.

There's a few places the Python library that do exactly that.

try:
value
except:
value = something

I admit it's something that should be avoided if possible because if
there's doubt that a name exists, then there would also be doubt
concerning where it came from and weather or not it's value/object is valid.

Anyway, it was an interesting but flawed idea, I should of thought more
about it before posting it.

Cheers,
Ron
 
D

Dan Sommers

I'm all for it. I would even be tempted of changing def to function,
but it would look stupid in:
class A:
function make_my_day(self):
return "Your day"
a = A()

since a.make_my_day() is really a method, not a standalone function.
We could use "function" instead of "lambda" though =)

So use "method" instead, which has the added advantage of implicity
declaring an extra argument named "this":

class A:
method __init__():
this.x = 0
method make_my_day(foo):
this.x += foo

there-aren't-enough-winks-in-the-universe'ly yours,
Dan
 
B

Bruno Desthuilliers

Tom Anderson a écrit :
Comrades,

During our current discussion of the fate of functional constructs in
python, someone brought up Guido's bull on the matter:

http://www.artima.com/weblogs/viewpost.jsp?thread=98196

He says he's going to dispose of map, filter, reduce and lambda. He's
going to give us product, any and all, though, which is nice of him.

What really struck me, though, is the last line of the abstract:

"I expect tons of disagreement in the feedback, all from
ex-Lisp-or-Scheme folks. :)"

I disagree strongly with Guido's proposals, and i am not an ex-Lisp,
-Scheme or -any-other-functional-language programmer; my only other real
language is Java. I wonder if i'm an outlier.

So, if you're a pythonista who loves map and lambda, and disagrees with
Guido, what's your background? Functional or not?

I discovered FP with David Mertz's papers about FP in Python. I had
never read nor write a line of lisp, scheme, haskell, caml etc before.
And I'd certainly start thinking of choosing another MYFL if anonymous
functions where to disappear from Python. Note that I said "anonymous
functions", not "lambda". Concerning map, filter, reduce etc, these
functions can live in a separate module, and this wouldn't bother me.
But anonymous functions are part of the language syntax, so there is no
work-around.

My 2 (euro) cents
 
B

Bruno Desthuilliers

Stian Søiland a écrit :
(snip)
Hey, I know!

t = python.util.ImmutableArrayList.fromCollection(L.getAbstractCollection())

python.util.functional.applyFunctionOnCollection(
(class implements python.util.functional.AnonymousFunction:
def anonymousFunction(x):
return x+1
), L)
Reminds me of something, but what ?-)
 
B

Benji York

Ron said:
"if extraargs:" would evaluate to "if None:", which would evaluate to
"if:" which would give you an error.

In what way is "if None:" equivalent to "if:"?
 
?

=?ISO-8859-1?Q?Daniel_Sch=FCle?=

I think in some contextes map is more readable than [f() for i in S]
because it's more verbatim
Removing lamdba would be reduce readability of Python, I think here
for examble of code like

class App:
....
....
def drawLines(self, event):
from random import randint
r = lambda : randint(1, 100)
self.canvas.create_line(r(), r(), r(), r())

defining one extra function would only confuse and
self.canvas.create_line(r(1, 100), r(1, 100), r(1, 100), r(1, 100))
is not very nice to look at

and what about creating one liner factories like
from math import log10
log = lambda basis: lambda x: log10(x) / log10(basis)
log2 = log(2)
log2(2**10) -> 10.0

I would consider it as a great loss for Python
if lambda will disappear
 
S

Steven Bethard

Daniel said:
Removing lamdba would be reduce readability of Python, I think here
for examble of code like

class App:
....
....
def drawLines(self, event):
from random import randint
r = lambda : randint(1, 100)
self.canvas.create_line(r(), r(), r(), r())

defining one extra function would only confuse and

But you just did define one extra function!!

If you're really afraid of two lines, write it as:

def r(): randint(1, 100)

This is definitely a bad case for an anonymous function because it's not
anonymous! You give it a name, r.
and what about creating one liner factories like
from math import log10
log = lambda basis: lambda x: log10(x) / log10(basis)
log2 = log(2)
log2(2**10) -> 10.0

This is slightly better, because at least one of your functions really
is anonymous. I'm not really sure I'm convinced that it's any better
than this though:

def log(base):
def log_in_base(x):
return log10(x)/log10(base)
return log_in_base

because when I first read the code, I didn't catch the second, nested
lambda. Of course, with a syntax-highlighting editor, I probably would
have.

Again though, to fix your abuse of anonymous function syntax for
non-anonymous functions, you should write this as:

def log(basis):
return lambda x: log10(x) / log10(basis)

Or if you're afraid of multiple lines:

def log(basis): return lambda x: log10(x) / log10(basis)

STeVe
 
D

David Abrahams

Tom Anderson said:
Comrades,

During our current discussion of the fate of functional constructs in
python, someone brought up Guido's bull on the matter:

http://www.artima.com/weblogs/viewpost.jsp?thread=98196

He says he's going to dispose of map, filter, reduce and lambda. He's
going to give us product, any and all, though, which is nice of him.

What really struck me, though, is the last line of the abstract:

"I expect tons of disagreement in the feedback, all from ex-Lisp-or-Scheme
folks. :)"

I disagree strongly with Guido's proposals, and i am not an ex-Lisp,
-Scheme or -any-other-functional-language programmer; my only other real
language is Java. I wonder if i'm an outlier.

So, if you're a pythonista who loves map and lambda, and disagrees with
Guido, what's your background? Functional or not?

Not. But I've gained a real appreciation for functional programming
from my use of both C++ and Python.
 
D

David Abrahams

Bruno Desthuilliers said:
I discovered FP with David Mertz's papers about FP in Python. I had
never read nor write a line of lisp, scheme, haskell, caml etc before.
And I'd certainly start thinking of choosing another MYFL if anonymous
functions where to disappear from Python. Note that I said "anonymous
functions", not "lambda". Concerning map, filter, reduce etc, these
functions can live in a separate module, and this wouldn't bother me.
But anonymous functions are part of the language syntax, so there is no
work-around.

Actually I'm pretty sure there is. It should be possible to
re-implement the Boost Lambda library in Python:

http://www.boost.org/libs/lambda

Compared with in-language lambda support it would have the advantage
of brevity and clarity for very small functions, but there are lots of
disadvantages, too. I wonder how Guido would feel if people started
using a (relatively) slow library solution with odd warts as a
consequence of dropping real lambdas.
 
R

Ron Adam

Benji said:
In what way is "if None:" equivalent to "if:"?

It's not now.. but if None where to really represent the concept None,
as in not bound to anything, it would evaluate to nothing.

Given the statement:

a = None

And the following are all true:

a == None
(a) == (None)
(a) == ()
(None) == ()

Then this "conceptual" comparison should also be true:

if (None): == if ():
if (): == if:


Comparing if's like that wouldn't be a valid code of course, but it
demonstrates the consistency in which the comparison is made.

I think. ;-)

Of course this is all hypothetical anyways, so it could be what ever we
decide makes the most since, include not changing anything.

Cheers,
Ron
 
M

Mike Meyer

Ron Adam said:
So doing this would give an error for functions that require an argument.

def foo(x):
return x

a = None
b = foo(a) # error because a dissapears before foo gets it.

So how do I pass None to a function?
So they wouldn't propagate like you would expect.

Hmmm.... interesting that would mean... lets see.


1. var = None # removes ref var, this is ok

2. None = var # give an error of course

3. var = undefined_var # same as "var = None", that's a problem!

Ok... this must give an error because it would delete var silently!
Definitely not good. So going on, on that basis.

4. undefined == None # Special case, evaluates to True.

5. def foo():return None # same as return without args

6. x = foo() # Would give an error if foo returns None

Why? Shouldn't it delete x?
This might be an improvement over current behavior. Breaks a lot of
current code though.

I don't think so. I've programmed in langauges that gave undefined
variables a value rather than an exception. It almost inevitabley led
to hard-to-find bugs.

FORTRAN used to give all variables a type, so that a typo in a
variable name could well lead to a valid expression. The technic for
disabling this was baroque ("IMPLICIT BOOLEAN*1 A-Z"), but so common
they invented a syntax for it in later versions of FORTRAN ("IMPLICIT
NONE").

<mike
 
R

Ron Adam

Stian said:
Or what about a recursive generator?

a = [1,2,[[3,4],5,6],7,8,[9],[],]

def flatten(item):
try:
iterable = iter(item)
except TypeError:
yield item # inner/final clause
else:
for elem in iterable:
# yield_return flatten(elem)
for x in flatten(elem):
yield x

print list(flatten(a))


Ok, lets see... I found a few problems with the testing (and corrected
it) so the scores have changed. My sort in place routines were
cheating because the lists weren't reset between runs so it had the
advantage after the first time though of sorting already sorted list.
And Tom's recursive no copy had a bug which kept a reference to one of
it's arguments so it's output was doubling the list. And the hasattr
function was slowing everyone down, so I inlined it for everyone who
used it.

Using a 1000 item list and starting with a flat list and increasing the
depth (unflatten) to shallow, medium, and deep. (but not so deep to
cause recursion errors.)

And the winners are...



Python 2.3.5 (#62, Feb 8 2005, 16:23:02)
[MSC v.1200 32 bit (Intel)] on win32
IDLE 1.0.5

Size: 1000 Depth: 0
georges_recursive_flatten: 0.00212513042834
rons_nonrecursive_flatten: 0.00394323859609
toms_recursive_zerocopy_flatten: 0.00254557492644
toms_iterative_zerocopy_flatten: 0.0024332701505
devans_smallest_recursive_flatten: 0.011406198274
rons_nonrecursive_inplace_flatten: 0.00149963193644
stians_flatten_generator: 0.00798257879114

Size: 1000 Depth: 25
georges_recursive_flatten: 0.0639824335217
rons_nonrecursive_flatten: 0.0853463219487
toms_recursive_zerocopy_flatten: 0.0471856059917
toms_iterative_zerocopy_flatten: 0.188437915992
devans_smallest_recursive_flatten: 0.0844073757976
rons_nonrecursive_inplace_flatten: 0.0847048996452
stians_flatten_generator: 0.0495694285169

Size: 1000 Depth: 50
georges_recursive_flatten: 0.134300309118
rons_nonrecursive_flatten: 0.183646245542
toms_recursive_zerocopy_flatten: 0.0886252303017
toms_iterative_zerocopy_flatten: 0.371141304272
devans_smallest_recursive_flatten: 0.185467985456
rons_nonrecursive_inplace_flatten: 0.188668392212
stians_flatten_generator: 0.090114246364

Size: 1000 Depth: 100
georges_recursive_flatten: 0.248168133101
rons_nonrecursive_flatten: 0.380992276951
toms_recursive_zerocopy_flatten: 0.177362486014
toms_iterative_zerocopy_flatten: 0.741958265645
devans_smallest_recursive_flatten: 0.306604051632
rons_nonrecursive_inplace_flatten: 0.393641091256
stians_flatten_generator: 0.177185368532

Stians flatten generator is nearly tied with Tom's recursive zerocopy.
My nonrecursive inplace is faster for very shallow lists, but Tom's
quickly over takes it. I was able to improve my nonrecursive copy
flatten a bit, but not enough to matter. So Tom's recursive zerocopy is
the overall winner with Stian's flatten generator close behind and just
barely winning out in the very deep catagory. But they're all
respectable times so everyone wins. ;-)



And here's the source code.

Cheers, :)
Ron



# -------------------------------

import sys
import time

TIMERS = {"win32": time.clock}
timer = TIMERS.get(sys.platform, time.time)

def timeit(fn,*arg):
t0 = timer()
r = fn(*arg)
t1 = timer()
return float(t1-t0), r

# --------------------------------

def georges_recursive_flatten(seq):
return reduce(_accum, seq, [])

def _accum(a, item):
if hasattr(item, "__iter__"):
a.extend(georges_recursive_flatten(item))
else:
a.append(item)
return a


def rons_nonrecursive_flatten(seq):
a = []
while seq:
if hasattr(seq[0], "__iter__"):
seq[0:1] = seq[0]
else:
a.append(seq.pop(0))
return a


def toms_recursive_zerocopy_flatten(seq, a=None): #a=[] kept a
reference to a?
if a==None:
a = []
if hasattr(seq,"__iter__"):
for item in seq:
toms_recursive_zerocopy_flatten(item, a)
else:
a.append(seq)
return a


def toms_iterative_zerocopy_flatten(seq):
stack = [None]
cur = iter(seq)
a = []
while (cur != None):
try:
item = cur.next()
if hasattr(item,"__iter__"):
stack.append(cur)
cur = iter(item)
else:
a.append(item)
except StopIteration:
cur = stack.pop()
return a


def devans_smallest_recursive_flatten(seq):
if hasattr(seq,"__iter__"):
return sum([devans_smallest_recursive_flatten(item) for item in
seq], [])
else:
return [seq]


def rons_nonrecursive_inplace_flatten(seq):
i = 0
while i != len(seq):
if hasattr(seq,"__iter__"):
seq[i:(i + 1)] = seq # setslice takes iterators!
else:
i = i + 1
return seq


def flatten_generator(item):
try:
iterable = iter(item)
except TypeError:
yield item # inner/final clause
else:
for elem in iterable:
# yield_return flatten(elem)
for x in flatten_generator(elem):
yield x

def stians_flatten_generator(seq):
return list(flatten_generator(seq))

# ------------------------------------------

flattens = [
georges_recursive_flatten,
rons_nonrecursive_flatten,
toms_recursive_zerocopy_flatten,
toms_iterative_zerocopy_flatten,
devans_smallest_recursive_flatten,
rons_nonrecursive_inplace_flatten,
stians_flatten_generator
]


import random
import time
random.seed(time.time())
def rand_depth_sequence(seq,depth):
n = len(seq)*depth
nn = 0
while nn<n:
try:
step = random.randint(1,3)
start = random.randint(0,(len(seq)-step))
end = random.randint(start,start+step)
seq[start:end]=[seq[start:end]]
nn += 1
except:
pass
return seq
#print sequence

size = 1000
original = range(size)
for depth in [0,25,50,100]:
sequence = rand_depth_sequence(original[:],depth)
print "\nSize:",size," Depth:",depth
for flatten in flattens:
s = sequence[:] # make new copy!
tm, result = timeit(flatten,s)
if result != original: # check for valid output!
print "Result Error from", flatten
print original
print result
print sequence
print s
break
f_name = flatten.func_name
print "%s: %s%s" % (f_name, ' '*(35-len(f_name)),tm)
# clear values for next test
del result
del s


# ----
 
R

Ron Adam

Mike said:
So how do I pass None to a function?

You wouldn't. What would a function do with it anyway? If you wanted
to pass a neutral value of some sort, then you'd just have to pick
something else and test for it. Maybe we could use Nil as an
alternative to None for that purpose?

Why? Shouldn't it delete x?

That was my first thought as well.

It would cause all sorts of problems. One way to avoid those is to
insist that the only way to assign (delete) a name to None is by
literally using "None" and only "None" on the right side of the = sign.

Any undefined name on the right side would give an error except for None
itself.
I don't think so. I've programmed in langauges that gave undefined
variables a value rather than an exception. It almost inevitabley led
to hard-to-find bugs.

That is why the above should give an error I believe. ;)

FORTRAN used to give all variables a type, so that a typo in a
variable name could well lead to a valid expression. The technic for
disabling this was baroque ("IMPLICIT BOOLEAN*1 A-Z"), but so common
they invented a syntax for it in later versions of FORTRAN ("IMPLICIT
NONE").

It's been so long since I did anything if Fortran I've actual don't
recall any of it. :) '83-'84

I went from that to pascal, which I thought was a big improvement at the
time.

Cheers,
Ron
 
R

Reinhold Birkenfeld

Ron said:
Given the statement:

a = None

And the following are all true:

a == None
Okay.

(a) == (None)
Okay.

(a) == ()

Whoops! a (which is None) is equal to the empty tuple (which is not None)?
(None) == ()

Then this "conceptual" comparison should also be true:

if (None): == if ():
if (): == if:

I can't really see any coherent concept here.

Reinhold
 
S

Steven D'Aprano

Steven said:
If you're really afraid of two lines, write it as:

def r(): randint(1, 100)

This is definitely a bad case for an anonymous function because it's not
anonymous! You give it a name, r.

This is something I've never understood. Why is it bad
form to assign an "anonymous function" (an object) to a
name?

It isn't just that lambda _can_ create functions that
aren't bound to any name. That I get. But why is it
suppose to be wrong to bind such a function to a name?

Sure, if the lambda is so complicated that it becomes
unreadable, the usage case is wrong and a def should be
used instead. But I see nothing wrong with doing this:

func = lambda x: x**3 - 3*x**2

Why is it considered abuse of lambda to assign the
functions to a name? Is it an abuse of lambda to do this?

D = {"one": lambda noun: noun,
"two": lambda noun: noun + 's',
"many": lambda noun: 'lots of ' + noun + 's' }

assert D["two"]("python") == "pythons"
 
D

Duncan Booth

Steven said:
This is something I've never understood. Why is it bad
form to assign an "anonymous function" (an object) to a
name?

Because it obfuscates your code for no benefit. You should avoid making it
hard for others to read your code (and 'others' includes yourself in the
future).

Also, it obfuscates tracebacks: all lambda expressions will identify in
but if you define a function you can give it a said:
Why is it considered abuse of lambda to assign the
functions to a name? Is it an abuse of lambda to do this?

D = {"one": lambda noun: noun,
"two": lambda noun: noun + 's',
"many": lambda noun: 'lots of ' + noun + 's' }

assert D["two"]("python") == "pythons"
No, that is approaching a reasonable use of lambda, however I would still
be inclined to write it with functions. e.g.

def one(noun):
return noun

def two(noun):
return noun+'s'

def many(noun):
return 'lots of %ss' % (noun,)

D = dict(one=one, two=two, many=many)

although in this particular case I would probably just put format strings
in the dictionary:

def D(style, noun):
formats = dict(one="%s", two="%ss", many="lots of %ss")
return formats.get(style, "an indeterminate number of %ss") % (noun,)

assert D("two","python") == "pythons"
 
C

Chris Rebert (cybercobra)

Agreed, I dislike map and its ilk as well.
However, they are handy in some cases. I particularly like the way Ruby
deals with this problem. Instead of all these functions, internal
iterators and true anonymous blocks are used.
Case in point:

def gt_than_5(obj):
return obj > 5
results = filter(gt_than_5, seq)

becomes

results = seq.find_all do |item|
item > 5
end

This has the advantage of writing less code for the common cases by
having them builtin to the class. Instead of everyone needlessly
recoding these over and over again, they're implemented in one place.
This could be done by defining an abstract class that enumerable
objects inherit from. It's not practical, but I can dream, can't I? ;-)
Also, you don't have to define a separate testing function. Granted, in
this case, the test func is trivial, but when it's non-trivial, you
really notice the advantages.
Hi All--

Tom said:
Comrades,

"I expect tons of disagreement in the feedback, all from ex-Lisp-or-Scheme
folks. :)"

I disagree strongly with Guido's proposals, and i am not an ex-Lisp,
-Scheme or -any-other-functional-language programmer; my only other real
language is Java. I wonder if i'm an outlier.

So, if you're a pythonista who loves map and lambda, and disagrees with
Guido, what's your background? Functional or not?

I'm a pythonista who doesn't love them. In fact, even though I've done
more than my fair share of lambda Tkinter programming using lambdas,
I've never been happy with lambda. And I've spent months inside of
Lisp/Emacs Lisp/Scheme, too (I have the world's second largest .emacs
file [my friend Andy Glew has the largest], even though I can't use it
on Windows;-). I find list comprehensions easier to understand than
map, and small named functions or, better yet, class methods, *tons*
easier to read/understand than lambda--there are too many restrictions
you have to remember.

Personally, I find that Lisp & its derivatives put your head in a very
weird place. Even weirder than PostScript/Forth/RPN, when you come
right down to it.

I won't miss them, but since I don't use them now, that doesn't mean a
whole lot.

Metta,
Ivan
----------------------------------------------
Ivan Van Laningham
God N Locomotive Works
http://www.andi-holmes.com/
http://www.foretec.com/python/workshops/1998-11/proceedings.html
Army Signal Corps: Cu Chi, Class of '70
Author: Teach Yourself Python in 24 Hours
 
D

Dennis Lee Bieber

Agreed, I dislike map and its ilk as well.
However, they are handy in some cases. I particularly like the way Ruby
deals with this problem. Instead of all these functions, internal
iterators and true anonymous blocks are used.
Case in point:

def gt_than_5(obj):
return obj > 5
results = filter(gt_than_5, seq)

becomes

results = seq.find_all do |item|
item > 5
end
Unfortunately, that simple case doesn't really assist your
viewpoint -- isn't it the same as the one-liner list-comp

results = [ x for x in seq if x > 5 ]

For this example, I find the list-comp cleaner than either of
the variants.

--
 
S

Steven D'Aprano

Because it obfuscates your code for no benefit. You should avoid making it
hard for others to read your code (and 'others' includes yourself in the
future).

I don't particularly think I'm that much smarter than the average
programmer. In fact I *know* that I'm not that much smarter. So why do I
see nothing obfuscated or obscure or difficult to understand in func =
lambda x: x**3 - 5*x when apparently most of the Python community find it
too complicated?

Whichever is "more readable" in the absolute sense, the "abused" lambda
expression above is within a gnat's whisker of the def equivalent,

def func(x):
return x**3 - 5*x

I honestly don't understand why it is supposed to be so hard to follow.

I can think of many function which should not be written with lambda, just
as some things shouldn't be written as list comps. But within the limits
of how much complexity you can reasonably include in a single expression,
I don't see why lambda puts people off.

I make it, eight mental tokens (not necessarily the same as Python tokens)
for the lambda versus nine for the def. A trivial difference. In my mind,
the tokens are:

func, =, lambda, x, :, x**3, -, 5*x

compared to:

def, func, (), x, :, return, x**3, -, 5*x

(Your mental parser may differ.)

Also, it obfuscates tracebacks: all lambda expressions will identify in
tracebacks as <lambda>, but if you define a function you can give it a
meaningful name.

Well there is that. If you have lots of lambdas assigned to names, I guess
debugging could be more difficult:

py> f = lambda x: 1.0/x
py> f(0)
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 1, in <lambda>
ZeroDivisionError: float division


py> def f(x):
.... return 1.0/x
....Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 2, in f
ZeroDivisionError: float division

So far so good. But then:

py> g = f
py> del f
py> g(0)
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 2, in f
ZeroDivisionError: float division

(but we actually got the error by calling g, not f, and in fact f no
longer exists at the point we called g)

Why is it considered abuse of lambda to assign the
functions to a name? Is it an abuse of lambda to do this?

D = {"one": lambda noun: noun,
"two": lambda noun: noun + 's',
"many": lambda noun: 'lots of ' + noun + 's' }

assert D["two"]("python") == "pythons"
No, that is approaching a reasonable use of lambda, however I would still
be inclined to write it with functions. e.g.

def one(noun):
return noun

def two(noun):
return noun+'s'

def many(noun):
return 'lots of %ss' % (noun,)

D = dict(one=one, two=two, many=many)

I find your version far more difficult to follow than mine.

Psychologically, I find that defs seem to carry significant mental weight
in a way that lambdas don't. Even though the lambda forms are
equivalent to the def forms, I find that the defs are more heavy-weight in
my conceptual map of the program than a lambda would be.

Put it this way: whenever I see a two-line def as above, I can't help
feeling that it is a waste of a def. ("Somebody went to all the trouble
to define a function for *that*?") Yet I would never think the same about
a lambda -- lambdas just feel like they should be light-weight.

Am I just weird?
 

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,769
Messages
2,569,581
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top