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   |   [EMAIL PROTECTED]   |   Brisbane, Australia
---------------------------------------------------------------
            http://boredomandlaziness.skystorm.net
--
http://mail.python.org/mailman/listinfo/python-list

Reply via email to