Monday, October 18, 2010

Real-world Functional Programming

There is a recurrent discussion in programming circles about the state-of-practice of functional programming languages, and the (presumably undeserved) little attention they get. It's curious to me that such arguments are usually centered on so-called "pure functional" languages such as Lisp, Scheme or Haskell (which isn't that "pure", but anyway), while totally ignoring how functional programming features have been consistently pouring into the mainstream programming landscape for more than a decade, through comparatively conservative efforts such as Javascript and Python.

As a matter of fact, I do functional programming in Python a lot; only not right away. Often, when working on a problem, I'll start with a simple imperative solution based on top-level functions. Then, as the domain creeps ever larger and passing around values becomes awkward, I factor in a basic object model with only essential behavior moved to methods, while the bulk of processing remains on the functions.

Finally, as recurring algorithms emerge, I start to refactor them into general implementations, customizable through object or function arguments. Eventually, most of my code is collected into highly general "portfolio" functions, while the "real" functions are mostly constructed by mixing and matching those. As a side-effect, closures and lambda functions abound.

This approach doesn't have much of the obsessive recursivity found in classical functional programming (although I've at times marveled at the mind-blowing length of the function invocation chains it produces), but it does rely on the first-citizenship status Python grants to functions – in fact it wouldn't work otherwise. It isn't "pure" functional, as it isn't "pure" OO either; but it enables widespread code reuse, naturally leans toward cohesion & loose coupling, and is highly productive.

Purity is a fool's errand. Just as it's not practical to have a "pure" object-oriented language (even Java has allowed for something akin to top-level function with static methods and imports), successful functional languages will have to compromise in order to accommodate its design features and the pragmatic needs of daily coding.