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.

Fun (and not-so-fun) with Haskell and Scheme

Lately I’ve been poking around at some new-to-me programming languages, Haskell and Scheme. I don’t expect to use either of them in a serious, practal project (except maybe Scheme for scripting GIMP), but they are both “weird” enough that it’s fun to learn them and expand my horizons.

For Haskell, I’ve been following along with the brilliant and funny Learn You a Haskel for Great Good. It’s in a similar spirit to Why’s (Poignant) Guide to Ruby, but more instructive and less nonsensical, without being any less funny. In addition to being a highly readable and excellent learning resource, it’s also home to golden quotes like this:

You also can’t set a variable to something and then set it to something else later. If you say that a is 5, you can’t say it’s something else later because you just said it was 5. What are you, some kind of liar?

And totally irrelevant but highly amusing illustrations like this:

A cartoon octopus playing Guitar Hero.

I therefore assert that Learn You a Haskell is the most awesome guide to any programming language, ever.

Even with a great guide, though, Haskell is a lot to wrap your head around. Partly because of its functional nature, and partly because of its outlandish concepts like curried functions, partial application, and folding, Haskell busted my brain halfway through chapter 6. (Okay, in my defense, it was also 4 AM.)

But it seems like a really interesting language once you grasp it, so I plan to revisit it later.

I also dabbled in Scheme a little bit, following Teach Yourself Scheme in Fixnum Days. Unfortunately, Teach Yourself Scheme isn’t nearly as entertaining or thorough as Learn You a Haskell. It’s very dry reading, and unless analyzing macro expansions gets you off, you probably won’t find it too enjoyable.

But, I was already familiar with Lisp, so most of the concepts weren’t terribly foreign, and I didn’t need as much handholding. For the most part, I just needed an introduction to the terms and function syntaxes peculiar to Scheme. But therein lies a problem: there are lots of Scheme implementations, and they are all peculiar.

SchemeWiki.org lists some 70 different implementations of Scheme, and none of them are authoritative. Perhaps in an attempt to remain apolitical, very few of the lists I’ve found give any sort of indication of which ones are any good. Which are stable, efficient, easy to install and use? Which ones have the most users? What features do they support? Are they still actively developed? Which (if any) of the 6 or 7 Scheme standards are they compliant with? What quirks or extra behavior do they have?

Am I expected to download and try every implementation, devise tests and benchmarks to determine compliance, efficiency, and feature set, and then decide which one I want to use to learn the language? Not gonna happen. Even reading the web sites for every implementation is more effort than I’m willing to spend. If there were 2 or 3 to choose from, sure, but not 70.

In the end, I just said “screw it” and installed Gambit on the highly scientific basis that it has a cool name. But, I might use MzScheme for learning, since that’s what Teach Yourself Scheme uses, and I wouldn’t know the difference.

I’m still interested in learning more Scheme (at least enough to find out what’s so great about call/cc), but the learning experience so far has not been nearly as rewarding or entertaining as it has been with Haskell.

Maybe Scheme needs a tutorial with a sense of humor and an octopus playing Guitar Hero?

It couldn’t hurt.