Why functional Python matters

Jp Calderone exarkun at intarweb.us
Tue Apr 15 22:30:02 CEST 2003


On Tue, Apr 15, 2003 at 07:22:47PM -0000, Dave Benjamin wrote:
>
> [snip - comparisons to and examples from PHP]
> 
> Guido's recent musings in the newsgroups and on his presentation on "Python
> Regrets" have made me a bit uneasy. In particular, they brought to light the
> fact that he generally prefers the object-oriented style to the functional
> style and would like to "deprecate" certain features:
> 
>  - apply, to be replaced with *-notation
>   - map and filter, to be replaced with list comprehensions
>    - lambda
>    

  While they take getting used to, you can't say that list comprehensions
aren't functional.  They're not traditional-lisp functional, but that isn't
the only kind :)

>    Lambda has had the thorniest history of all of these, I think. Lambda has
> its roots in LISP and the Lambda calculus, and can be used to create
> "anonymous functions" at runtime that can be passed around as needed. This
> is a very powerful and useful feature for functional programming, as well as
> for event-driven programming. It baffles me that anyone would want to remove
> it.

  No worries, there are enough people who would shout loudly enough were
this to be removed that its existence is safe, at least for the near future.

  Just make sure you give a holler anytime someone suggests discarding them.

> [snip - default argument hacks, nested scopes]
> 
> The second "problem" that everyone seems to keep bringing up is that lambda
> limits you to expressions, not statements. This makes me laugh every time,
> because this is one of the things that I *loved* about Python when I was
> first learning it! If you get used to writing functions that only return
> expressions, you are on the road to understanding the functional style! One
> thing that I recommend that anyone try as a learning experience is this: try
> writing a program where every single function starts with "return". Better
> yet, write your whole program with lambdas. <screams from the back row> Of
> course, I don't recommend doing this sort of thing "out in industry", but I
> guarantee that you will learn to write code that is more reusable,
> side-effect free, and finely decomposed once you have gained some practice
> writing code this way.

  Lambdas are an excellent tool for obfuscation, that's for sure.  You're
right not to recommend overusing them in production code.  Generally, I try
to limit myself to the simplest expressions, on the order of "x and y" or
"result[index]", and translate to fully fledged functions for larger
expressions.  It's just easier to maintain.

  Also, note that lambdas *aren't* side-effect free, because Python isn't
side-effect free.  You can write ones that are, but then again, you can
write functions with "def" that are side-effect free too.

> 
> I would not like to see lambda support "statements". I think that would ruin
> a good thing. I would not like it removed from the language. I want it the
> way it is. The only thing between "lambda" and perfection is the name. It
> should be "fun" or something. If I had a lambda key on my keyboard, I would
> press it. <grin>

  Statements are, by definition, things which cannot appear in lambdas ;)
No worries here, I think.

> 
> "apply" is less of a big deal to me, but I'd still like to keep it because
> it allows for greater portability. I feel so more strongly about map and
> filter. Yes, I know about list comprehensions. I think they are wonderful, I
> thank Guido for adding them, I thank Haskell for inspiring them, and I don't
> want them to ever go away. But just because you can do a similar set of
> things with list comprehensions than with map and filter doesn't mean that
> they are completely redundant. In fact, I believe that it is advantageous to
> design functions specifically for use with map and filter. If you design
> this way, you will benefit from cleaner syntax than list comprehensions can
> offer. 

  Luckily, map() and filter() are implementable in terms of list
comprehensions.  So even in Python3k, when they're finally removed from the
language, you can implement them yourself in Python, and gain the
performance benefits of using a JIT on python bytecode ;)

> For example:
> 
>  - map(process_record, records)
>  
> compared with:
>  
>  - [process_record(record) for record in records]
>   
>   I'm aware that adding lambdas, nesting, multiple filters, etc. can make
> map/filter much less readable than list comprehensions, but functional
> decomposition is another solution. If you have to nest that much, perhaps
> your functions are too complicated and need to be broken up. I'm not saying
> that this is always the case, but for the sake of clarity - in certain
> situations - I greatly prefer map/filter to list comprehensions. For
> starters, they eliminate the need to name the temporary variable.

  I use both in my programs, but I find more and more that I only use
map/filter for the runtime speedup they sometimes provide.  Again, list
comprehensions are functional, just not in the same way.

> 
> Rather than remove these important functional built-ins, I would like to see
> two last built-ins be added: unzip (to reverse the behavior of zip), and
> curry (see the example by Alex Martelli, et. al. in the Python Cookbook,
> sec. 15.7). Anything else can be thrown into a "functional" standard module.
> The global namespace doesn't need any more clutter, and I sympathize with
> those who wish to reduce it, but--please!--not at the expense of the
> functions that form the foundation of functional programming!

  The inverse of zip is already available (and with one less character than
unzip! ;).  x == zip(*zip(x)) (ignoring sequence types, of course).

> [snip - flexibility of Python]
> 
> Finally, I'd like to make one comment about Perl. I think that this is
> important and relevant. There is clearly a difference in philosophy between
> Perl culture and Python culture. Perl says There's More Than One Way To Do
> It, and Python begs to differ. Perl is all-inclusive, Python is more
> exclusive. However, let's not get carried away with the exclusivity! There
> are clearly multiple of ways of doing many things in Python, and that's not
> a bad thing. Sometimes you want a list, other times you want an iterator.
> Sometimes you want a list comprehension, other times you want map/filter.
> Closures? Objects! Dispatches? Polymorphism! Inheritance? Composition? Just
> because Perl says you can do anything any-which-way doesn't mean that to
> compete Python should force you to a single method of problem-solving.

  I don't think Python is headed the way of Unlambda, don't worry :)

> 
> Perl is a beautiful thing. It encourages more creativity in the sense of
> language design than any other language I have ever used, including Python.
> There are many things to learn from Perl, and open-mindedness is one of
> them. Java, on the other hand, is extremely rigid about its way of doing
> things--trying to do functional programming in Java requires the use of
> bulky wrapper classes instead of true, lightweight higher-order functions,
> and its lack of parametric polymorphism makes the entire type system a pain
> in the butt.

  What I think is an important distinction to make here is the language vs
the library.  Right now, there are overlapping language features.  I'd much
prefer it if some of the things, even the useful things like map(), were
re-implemented in terms of other Python features and moved out of the
language and into the library.  This gives the best of both worlds - a
language simple to learn and use that also provides an expressive set of
features through its stdlib.

> 
> Python is a nice happy medium between regularity and freedom. I'd like to
> see it stay that way.
> 

  Jp

-- 
Somewhere, something incredible is waiting to be known.
                -- Carl Sagan
-- 
 up 26 days, 17:02, 6 users, load average: 1.06, 1.16, 1.12





More information about the Python-list mailing list