I’ve been reading Real World Haskell lately in order to get a better grasp on Haskell and functional programming. It’s a book I’d highly recommend—especially when it’s done!

One of the fundamental building-blocks of Haskell is the foldr method which, I am told, is called a “primitive recursive” function because it is capable of building any function in a set of useful recursive functions (e.g. foldl, map, filter, etc.) This is really important to me, because I had always liked foldl before, which seemed more intuitive (i.e. it iterates through a list from left to right, which is my natural way of thinking of lists). Anyway, it turns out that foldr can be used to build foldl, but not vice-versa, which proves foldr is more “primitive”.

One of the exercises in the Real World Haskell book is to create the concat function which takes a list of lists and turns them into one list. I spent about an hour trying various recursive tricks last night, and realized that this is a double-recursive problem—you need an append function available before you can recursively join a list of indefinite length.

What really delighted me in the end was that both the append and the concat functions can be very easily defined in terms of “foldr”:

myAppend a b = foldr (:) b a
myConcat = foldr myAppend []

In the first definition, myAppend is using foldr to replace the last (empty) element of the list with “b” (the list to be appended) and then consing each element in a onto the front of that list.

In the second definition, myConcat is using foldr to start with an empty list and then append prepend each element of the outer list with a previous element of that list (i.e. the parameter passed to myConcat is expected to be a list of lists).

Since myAppend is just the concatenation of two lists, it is exactly the same as the (++) operator in Haskell. So, the concat function can concisely be defined as:

myConcat = foldr (++) []

This code makes use of currying, which means that I’m defining a function that uses another function with incomplete parameters (in this case, I’ve only passed two parameters to foldr when three are normally required). The first function expects an anonymous parameter (i.e. the list of lists) which will get passed into foldr, thus completing the foldr function.

Update: I just found an even more concise way to define concat (assuming ++ is not available), thanks to the help on #haskell:

myConcat = foldr (flip (foldr (:))) []

That’s one reason Haskell is “precision engineering for programmers” :)