Is this a good use for lambda
Nick Coghlan
ncoghlan at iinet.net.au
Tue Dec 21 04:58:56 EST 2004
Alan G Isaac wrote:
> I need a clarification of the argument.
> Are the opponents saying that I should not be able to:
>
> def compose(list_of_functions): return reduce(lambda f, g: lambda x:
> f(g(x)), list_of_functions)
As things stand, I can live with lambda. However, if something can't be said in
a single expression, then it's too complicated to be embedded inside another
statement and have the whole remain even remotely readable.
Even the above example is impossible to parse easily unless you happen to
recognise that the 'compose' means 'function composition'. (cf. Fredrik's
reaction. . .)
> In a nutshell: why?
I dislike the use of lambda here, because it isn't very readable for most
people, and readability counts. To actually understand what this code does, I
had to rewrite it as I have below.
To parse a statement using lambdas and figure out what it does, one almost *has*
to assign a mental name to each lambda. Why should every reader of the code have
to go to that effort, when the author of the code can do it once, and provide
premade mental handles for every code reader to come after them?
> And may I see the proposed "better" replacement for function composition.
Moving to a programming world where whitespace and typed characters are so cheap
as to be practically free:
def compose(list_of_functions):
def compose_pair(f, g):
def composed_pair(x):
f(g(x))
return composed_pair
return reduce(compose_pair, list_of_functions)
The advantage of this version is that what it does is fairly obvious, even to
someone that doesn't often use the term 'function composition' (like, say, me -
I know what it means, but it doesn't spring to mind naturally).
Moving on, I'd suggest that for any significant list of functions, the
performance of the recursive version is going to be lousy, and I'd rewrite it
with the iterative version:
def compose(list_of_functions):
application_order = reversed(list_of_functions)
def composed(x):
for f in application_order:
x = f(x)
return x
return composed
With this last version, even people that don't use functional programming at all
can see immediately what the function is doing, including what the order of
application is for the functions that combine to give the overall function
composition (I had to go look up the precise operation of reduce() to be sure I
had the order of application for function composition correct). The initial
creation is going to be much faster (creating a single function object, rather
than a big stack of them), and the actual invocation is going to be faster
(since it's a simple iteration, rather than a big chain of recursive function
calls).
What are the disavantages of my final version?
1. It will deeply offend the aesthetic sensibilities of any functional purists
in the audience.
2. It no longer directly implements the theoretical concept of function
composition (although it has the same effect).
From a real world programming point of view, though, it's self-documenting,
runs faster and uses less memory, so it's really a pure win.
Cheers,
Nick.
--
Nick Coghlan | ncoghlan at email.com | Brisbane, Australia
---------------------------------------------------------------
http://boredomandlaziness.skystorm.net
More information about the Python-list
mailing list