[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Accumulator



> [snipped many other interesting points I don't have time to pick up now]
> 
> I don't think Guido ever intended that! Python programmers should do
> things in the Python way. State + Behaviour = Instance, not closure.
> 
> > .... I was kind of shocked, for example, to
> > find that you can't put the same things in the body of a
> > lambda expression as you can in a named function.  That
> > just seems like a bug to me.
> 
> You're right, it is a bug. But you're missing something. Adding lambda
> to an OO language was a bug to start with. Guido hasn't "fixed" lambda
> because he wants it to go away. Trying to be Lisp was the mistake.

I really have troubles understanding the continual moans about lambda -- I
don't think it's buggy (it was, before nested scopes) and I don't think adding
lambda to the language was a mistake to start with either (whatever Guido's
thoughts on the matter may be). In fact, I find python's lambda just about
perfect -- maybe I'm missing something.

When a really simple function is all that's needed lambda gives more
readability. It is more compact, you don't have to make up a silly name and
because it is defined where it is used, the reader doesn't have to go
searching for the function definition, which over time might have wandered
quite a bit away.

Compare:

  plot(lambda x: 3 * sin(x) ** 2)

to 

  def plotFunc1(x):
      return 3 * sin(x) ** 2
  # ... maybe some stuff that was inserted later
  plot(plotFunc1)

However if you want a function that contains more than one simple expression
you can always (and presumably should) use def instead -- IMHO allowing
lambdas that are are fully equivalent to defs would just lead to more
spaghetti code, without adding any expressiveness to the language. Moreover
overly complicated functions for which you can't come up with a name more
likely than not are a sign of poor structure and potential code redundancy.

Here are a few exampels of when I think it's best to use lambda:

Default arguments: 
        def position(seq, item, test=lambda x,y: x is y):...

  I much prefer this style to 
        ...test=None):
           ...
           if test is None: ...

Currying, composition and argument swapping: 
         lambda x: foo(y,x)
         lambda x: foo(bar(x))
         lambda x,y: y / x

Delayed evaluation: 
         lambda: doSomething()


Of course, one could write dedicated curry, composition etc. functions and
indeed people have, including myself. But I think in most cases lambda wins
out over these constructs, because it is often just as concise, the semantics
are immediately transparent, it is more flexible (e.g. if you want to curry
but swap the order of arguments) and people can intuitively understand and use
it without having ever heard of currying or composition. 


> 
> "Q. What feature of Python are you least pleased with? 
> 
> Guido: Sometimes I've been too quick in accepting contributions, and
> later realized that it was a mistake. One example would be some of the
> functional programming features, such as lambda functions. lambda is a
> keyword that lets you create a small anonymous function; built-in
> functions such as map, filter, and reduce run a function over a sequence
> type, such as a list."
> 
> He wrote that before Python had grown readable alternatives to map,
> filter and apply. It is even more true now that you can do stuff like
> this:
> 
> mult3 = [3 * x for x in numbers]
> evens = [x for x in numbers if x % 2 == 0]
> 

Yes, I agree that for many cases comprehensions can be clearer, but I also
think for many they aren't, notably when you've got more than one sequence:

      map(add, xs, ys)

is, to me, better than:

    [x + y for (x,y) in zip(xs,ys)]

which in turn is better than:

      sums = []
      for i in range(len(xs)):
          sums.append(xs[i] + ys[i])

in fact, as long I have a ready-made function, I'd prefer map:

   map(str, args)

Also, this style of programming naturally extends to lazy sequences (if you
define things like, say xzipWith etc.), dictionaries and other scenarios that
you can't accommodate with comprehensions or that are awkward and ugly with
loops (e.g. reduce'ing). People who are have been forced by their previous
languages to iterate over integers in a loop when they wanted to deal with any
type of container, might find this style less obvious on first sight, but I
really like to think in terms of manipulating streams of data by channeling
them trough functions -- and I haven't been brought up with functional
programming languages, in case you wonder. I just began to develop a distaste
for loops and variables that change values over time, because I find them
often more error-prone and less elegant and concise (oops -- incremented foo
one line too early...; oops forgot to initialize foo correctly... etc.). If
this doesn't convince you, I'd suggest you have a look at Numerics ufuncs,
compare it to matlab and see how much more elegant and powerful this design
is. I'm not denying that one can get carried away and that loops are sometimes
clearer. Of course 'clear' also depends how used one is to a certain style of
coding (e.g. do you find ``reduce(operator.getitem, pos, tree)`` clear? I
certainly do).

> Also, lambda in Python is merely syntactic sugar for the function
> definition feature that Python has had since 1.0. It is a crippled form
> of an existing feature. A clear bug that arose from "Lambda envy."

Well clear to you, maybe :)

alex