99% Pure Functional Programming
In my recent adventures in Haskell and Scheme, I was immersed in the concept of functional programming. Haskell in particular has a strong relation with the notion of pure functions, i.e. functions without side effects. A pure function does nothing except calculate and return some value based on the input parameters.
I like pure functions, and I try to write them where I can. But Haskell is billed as a “purely functional programming language”. This perplexed me. How could there be an entire programming language that was purely functional? Or, rather, how could you use such a language to actually do anything useful?
Consider this: if you're restricting yourself to absolutely no side effects, you're not allowed to write to files, send data over a network, print text to the console, draw images on the screen, or anything like that. (So much for any ideas of writing a game in a purely functional language!) A program with no side effects is a sort of black hole: parameters can go in, but nothing comes out (except the program exit status code, which is the “return value” of the program). The user doesn't see anything, no files are changed, no packets sent over the network. The program leaves behind no legacy: the system is in much the same state after the program has run as it was before the program ran.
And yet, at least one useful bit of software has been written in Haskell: the darcs revision control system. So what's the secret? How did they do it?
Well, it's simple: Haskell isn't entirely pure. It's “tainted” with some functions that do have side effects, such as writing to files and printing text.
Granted, it's noteworthy that Haskell can get by without many other common side effects, like editing strings or lists in-place, modifying object state, or keeping global variables. It does force you to think in a functional way, and to break many bad habits. And striving for functional programming, regardless of the language you are using, often results in cleaner, less buggy, and easier to maintain code.
But at the end of the day, if you want to accomplish anything, you have to make some concessions to imperative programming. There has to be a side effect somewhere.