(Boy is there a lot of Haskell here now. What’s up with that?)

This one comes by way of Shachaf Ben-Kiki, who found it originally and mentioned it to me.

Data.Traversable and Data.Foldable are two Haskell typeclasses that express related notions of a data structure being “list-like” in the sense that it contains zero or more elements, and an externally-provided function can be mapped over those elements in some way.

GHC provides support (as a language extension) for automatically “deriving” instances of these type classes for algebraic data types; Essentially this asks the compiler to generate the “obvious” code to traverse your data structure in the appropriate way.

In GHC prior to 7.8, given a classic definition of a cons-cell list:

data List a = Nil | Cons a (List a)

GHC would derive a Foldable instance that looks something like this:

instance Foldable List where foldr f z Nil = z foldr f z (Cons x xs) = f x (foldr (\a b -> f a b) z xs)

The bug arises from the unnecessary eta-expansion of f in the second line. A list N elements long will recurse into Cons case N times, and each time f will get wrapped in a no-op lambda. When the evaluations are finally forced, we get a series of evaluations of expressions like:

f a b (\a b -> f a b) a b (\a b -> (\a b -> f a b) a b) a b (\a b -> (\a b -> (\a b -> f a b) a b) a b) a b …

This is a classic “triangle” pattern of evaluations, resulting in O(N²) reductions and thus runtime.

The fix involved tweaking the code generator to not produce the extra lambdas, which were essentially only there as a quirk of the abstractions used in the code generation.