Learn Me a Haskell

April 26, 2012 at 8:50 pm
filed under Coding

I’ve been wanting for some time to delve into functional programming (FP). As I’m sure I’ve said eleventy-billion-and-one times, I got a taste of some FP patterns in Ruby and JavaScript, and Python to a lesser extent. Well, now I have: I’ve been reading Learn You a Haskell for Great Good!.

Rationale

The fewer lines of code there are, the fewer bugs you’re likely to have. Generally, if you can say a lot with fewer words, without loss of precision or intelligibility, it’s a good idea. It’s also a good idea to push complexity down by using language features or standard libraries to do the heavy lifting for you.

What I find attractive about functional programming patterns like higher order functions is that it allows you to push some of the complexity downward, into the language or standard libraries, without losing expressiveness. You can say more with fewer words. If we want to accumulate a list of even numbers between 1 and 20 in Java, it ends up looking something like this:

List<Foo> fooList = getFooList();
List<Foo> fooBarList = new List<Foo>();
for (Foo f : fooList) {
  if (f.hasBar()) {
    fooBarList.add(f)
  }
}

This example is a bit contrived, but not terribly so. Filtering a list of items is relatively common, and despite that, this has a lot of lines for such a simple, common operation.

Lest it seem like I’m picking on Java, I’ll show you a rough equivalent in Go:

fooList := getFooList()
var fooBars []Foo
for _, f := range fooList {
  if (f.HasBar()) {
    fooBars = append(fooBars, f)
  }
}

We have less boilerplate in terms of declaring variable types, but it’s still a lot of lines for filtering a list on a simple boolean test.

I pick on Python a lot, but this is extremely simple in Python:

foos = GetFooList()
foo_bars = [f for f in foos if f.HasBar()]

This, I would say, is a nearly perfect ratio of lines-to-operations. You could even replace foo_list with GetFooList(), but let’s not get carried away. Ruby takes this even further and provides a number of similar patterns for the Array class.

I know this is crazy talk, but I think this is extremely powerful. You can express your intent very clearly in fewer lines. Your readers (yes, readers) are free to focus on what you are doing instead of how.

If you read about FP, you’ll also hear a lot about state. The notion is that if you’ve got methods attached to a class, the state of that class is implicit input to any given method. Coming from a testing perspective, I believe this makes a class harder to unit test. Sometimes you must store state, obviously, but in general a method which has explicit inputs and outputs is easier to test. (I suppose this is also applicable to trying to reason about what a method does mathematically.)

What was sort of revelatory to me is that, actually, a lack of mutable state isn’t so crazy (h/t Haskell Amuse-Bouche). If you’ve used *nix for getting work done, you’ve probably done something like this:

grep -o 'foo.*bar' ~/baz | awk '{print $1}' | sort | uniq -c

None of those are actually changing any state. You’re just filtering input. If you take the above — avoid state, give functions explicit input/output — to a reasonable conclusion, what you end up with is a glorified pipeline like what you see above. And this is one of the ideas behind Haskell.

A simple example and then done

In Haskell, you can compose a series of functions pretty easily, like this:

map (negate . abs) [5,-3,-6,7,-3,2,-19,24]

It’s a slightly goofy math example ripped off from Learn You a Haskell, but you get the idea. We chain together functions negate and abs as one function, and then map that onto the following list.

The concision here is impressive, although I find “real” Haskell considerably more difficult to read so far. Haskell programmers are very fond of one-letter variables and the syntax itself is so expressive in part because it is so concise. If you can decode it, it starts to become beautiful, but it’s that decoding part I still struggle with.

As I delve more into Haskell, I’ll probably blog about it. This is enough for now, though.

%d bloggers like this: