Why isn't Python very good for functional programming?

PythonFunctional Programming

Python Problem Overview


I have always thought that functional programming can be done in Python. Thus, I was surprised that Python didn't get much of a mention in this question, and when it was mentioned, it normally wasn't very positive. However, not many reasons were given for this (lack of pattern matching and algebraic data types were mentioned). So my question is: why isn't Python very good for functional programming? Are there more reasons than its lack of pattern matching and algebraic data types? Or are these concepts so important to functional programming that a language that doesn't support them can only be classed as a second rate functional programming language? (Keep in mind that my experience with functional programming is quite limited.)

Python Solutions


Solution 1 - Python

The question you reference asks which languages promote both OO and functional programming. Python does not promote functional programming even though it works fairly well.

The best argument against functional programming in Python is that imperative/OO use cases are carefully considered by Guido, while functional programming use cases are not. When I write imperative Python, it's one of the prettiest languages I know. When I write functional Python, it becomes as ugly and unpleasant as your average language that doesn't have a BDFL.

Which is not to say that it's bad, just that you have to work harder than you would if you switched to a language that promotes functional programming or switched to writing OO Python.

Here are the functional things I miss in Python:


  • No pattern matching and no tail recursion mean your basic algorithms have to be written imperatively. Recursion is ugly and slow in Python.
  • A small list library and no functional dictionaries mean that you have to write a lot of stuff yourself.
  • No syntax for currying or composition means that point-free style is about as full of punctuation as explicitly passing arguments.
  • Iterators instead of lazy lists means that you have to know whether you want efficiency or persistence, and to scatter calls to list around if you want persistence. (Iterators are use-once)
  • Python's simple imperative syntax, along with its simple LL1 parser, mean that a better syntax for if-expressions and lambda-expressions is basically impossible. Guido likes it this way, and I think he's right.

Solution 2 - Python

Guido has a good explanation of this here. Here's the most relevant part:

> I have never considered Python to be > heavily influenced by functional > languages, no matter what people say > or think. I was much more familiar > with imperative languages such as C > and Algol 68 and although I had made > functions first-class objects, I > didn't view Python as a functional > programming language. However, earlier > on, it was clear that users wanted to > do much more with lists and functions. > > ... > > It is also worth noting that even > though I didn't envision Python as a > functional language, the introduction > of closures has been useful in the > development of many other advanced > programming features. For example, > certain aspects of new-style classes, > decorators, and other modern features > rely upon this capability. > > Lastly, even though a number of > functional programming features have > been introduced over the years, Python > still lacks certain features found in > “real” functional programming > languages. For instance, Python does > not perform certain kinds of > optimizations (e.g., tail recursion). > In general, because Python's extremely > dynamic nature, it is impossible to do > the kind of compile-time optimization > known from functional languages like > Haskell or ML. And that's fine.

I pull two things out of this:

  1. The language's creator doesn't really consider Python to be a functional language. Therefore, it's possible to see "functional-esque" features, but you're unlikely to see anything that is definitively functional.
  2. Python's dynamic nature inhibits some of the optimizations you see in other functional languages. Granted, Lisp is just as dynamic (if not more dynamic) as Python, so this is only a partial explanation.

Solution 3 - Python

Scheme doesn't have algebraic data types or pattern matching but it's certainly a functional language. Annoying things about Python from a functional programming perspective:

  1. Crippled Lambdas. Since Lambdas can only contain an expression, and you can't do everything as easily in an expression context, this means that the functions you can define "on the fly" are limited.

  2. Ifs are statements, not expressions. This means, among other things, you can't have a lambda with an If inside it. (This is fixed by ternaries in Python 2.5, but it looks ugly.)

  3. Guido threatens to https://www.artima.com/weblogs/viewpost.jsp?thread=98196">remove map, filter, and reduce every once in a while

On the other hand, python has lexical closures, Lambdas, and list comprehensions (which are really a "functional" concept whether or not Guido admits it). I do plenty of "functional-style" programming in Python, but I'd hardly say it's ideal.

Solution 4 - Python

I would never call Python “functional” but whenever I program in Python the code invariably ends up being almost purely functional.

Admittedly, that's mainly due to the extremely nice list comprehension. So I wouldn't necessarily suggest Python as a functional programming language but I would suggest functional programming for anyone using Python.

Solution 5 - Python

Let me demonstrate with a piece of code taken from an answer to a "functional" Python question on SO

Python:

def grandKids(generation, kidsFunc, val):
  layer = [val]
  for i in xrange(generation):
    layer = itertools.chain.from_iterable(itertools.imap(kidsFunc, layer))
  return layer

Haskell:

grandKids generation kidsFunc val =
  iterate (concatMap kidsFunc) [val] !! generation

The main difference here is that Haskell's standard library has useful functions for functional programming: in this case iterate, concat, and (!!)

Solution 6 - Python

One thing that is really important for this question (and the answers) is the following: What the hell is functional programming, and what are the most important properties of it. I'll try to give my view of it:

Functional programming is a lot like writing math on a whiteboard. When you write equations on a whiteboard, you do not think about an execution order. There is (typically) no mutation. You don't come back the day after and look at it, and when you make the calculations again, you get a different result (or you may, if you've had some fresh coffee :)). Basically, what is on the board is there, and the answer was already there when you started writing things down, you just haven't realized what it is yet.

Functional programming is a lot like that; you don't change things, you just evaluate the equation (or in this case, "program") and figure out what the answer is. The program is still there, unmodified. The same with the data.

I would rank the following as the most important features of functional programming: a) referential transparency - if you evaluate the same statement at some other time and place, but with the same variable values, it will still mean the same. b) no side effect - no matter how long you stare at the whiteboard, the equation another guy is looking at at another whiteboard won't accidentally change. c) functions are values too. which can be passed around and applied with, or to, other variables. d) function composition, you can do h=g·f and thus define a new function h(..) which is equivalent to calling g(f(..)).

This list is in my prioritized order, so referential transparency is the most important, followed by no side effects.

Now, if you go through python and check how well the language and libraries supports, and guarantees, these aspects - then you are well on the way to answer your own question.

Solution 7 - Python

Python is almost a functional language. It's "functional lite".

It has extra features, so it isn't pure enough for some.

It also lacks some features, so it isn't complete enough for some.

The missing features are relatively easy to write. Check out posts like this on FP in Python.

Solution 8 - Python

Another reason not mentioned above is that many built-in functions and methods of built-in types modify an object but do not return the modified object. If those modified objects were returned, that would make functional code cleaner and more concise. For example, if some_list.append(some_object) returned some_list with some_object appended.

Solution 9 - Python

In addition to other answers, one reason Python and most other multi-paradigm languages are not well suited for true functional programming is because their compilers / virtual machines / run-times do not support functional optimization. This sort of optimization is achieved by the compiler understanding mathematical rules. For example, many programming languages support a map function or method. This is a fairly standard function that takes a function as one argument and a iterable as the second argument then applies that function to each element in the iterable.

Anyways it turns out that map( foo() , x ) * map( foo(), y ) is the same as map( foo(), x * y ). The latter case is actually faster than the former because the former performs two copies where the latter performs one.

Better functional languages recognize these mathematically based relationships and automatically perform the optimization. Languages that aren't dedicated to the functional paradigm will likely not optimize.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDavid JohnstoneView Question on Stackoverflow
Solution 1 - PythonNathan Shively-SandersView Answer on Stackoverflow
Solution 2 - PythonJason BakerView Answer on Stackoverflow
Solution 3 - PythonJacob BView Answer on Stackoverflow
Solution 4 - PythonKonrad RudolphView Answer on Stackoverflow
Solution 5 - PythonyairchuView Answer on Stackoverflow
Solution 6 - PythonxenoView Answer on Stackoverflow
Solution 7 - PythonS.LottView Answer on Stackoverflow
Solution 8 - PythonDvd AvinsView Answer on Stackoverflow
Solution 9 - Pythonuser2074102View Answer on Stackoverflow