Benefits of Functional Programming

A friend asks:

[Functonal Programming in Python] is an interesting way to see things. I find it fascinating, but what do you think is the main benefit? For example, lambdas are cool syntactically, but I don't see a huge reason for them other than sugar. Python seems to treat function objects basically like function pointers in C, and lambdas are like safe, single expression C macros that you loop through lists. Does functional programming offer more than syntax? Even if it's merely syntax to help one think in a different paradigm that's valid, but I'm struggling to see the value here in the beginning, whereas with C++ the benefits of OOP was easily apparent.

In addition to passing first class functions and having APIs with callbacks, etc., one of the main benefits to functional programming revolves around state. All old state is never updated or copied or klobbered in-place, but is kept around as is. All data structures in purely functional languages are 100% immutable. This eliminates large classes of bugs (but makes coding certain kinds of complex state updates a little more awkward, honestly) and makes testing easier and more mathematical. This also allows 'time-travel' or 'undo' or rewind at the granular level.

(See Immutable.JS, persistent data structures in JavaScript.)

These special vector collections and hash maps (dictionary / object), based on work by the late Phil Bagwell, allow basically O(1) lookups and appends with no copying. (There is more overhead/book-keeping than normal low-level C-style data structures but the Big-O performance is still shockingly amazing and scalable.)

This fits with the expression-based approach that most FP languages encourage because you can usually write code that describes declaratively how to compute something, instead of the steps and order to compute it. And those functions can be tested independently since there is little or no 'implicit runtime state' to have to supply at testing time.

Imagine looking at a code base and seeing each function in isolation and knowing (Haskell, at least!) that each piece of code completely and explicitly tells you what inputs it takes, and what output it computes, and that each function has zero side effects (and hence no other effect on any other code ever, just taking CPU time and allocating some memory and returning a result). This also means that if you can prove (formally or informally) that a set of functions are correct for all of their individual inputs, and a combining function is correct, then the combination of those functions is guaranteed to be correct. In normal programming, this is not the case because of implicit, hidden global (or localized) runtime state. When refactoring a chunk of imperative (non-FP) code, what you often end up doing is making the inputs explicit, etc. so that the block of code can be cut out and isolated and used anywhere else. In FP this is already done, every where!

FP is not a panacea but purely functional (stateless) coding style (in C#/C++ = static classes with only static methods and no static mutable state) is awesome because it makes all dependencies explicit instead of hiding state in a 'this' object, which is just a slightly more abstract version of the global state anti-pattern—now your global state is just hidden behind myriad objects! Purely functional code can be used anywhere 'as-is' and expected to work in all circumstances, with no semantic (incorrectness) penalties for reordering calls to functions, etc. You can write large amounts of code in OOP languages in a purely FP coding style and get 90% of the benefit of FP, (but you will still wonder about that last 10%). For example, objects with no mutable state, just set their fields once in the constructor, and provide methods that compute things but do not mutate internal state, etc.