Deriving length better: missing method problem

David Feuer david.feuer at gmail.com
Sun Apr 2 20:56:44 UTC 2017


GHC 8.4 DeriveFoldable will derive the definition of `null` rather
than falling back on the default. This can produce dramatic
performance improvements. I would like to do the same for `length`,
but unfortunately, there's a problem.

### Why I want to derive length

Consider the declaration

    data Foo a = Foo (Map "String" a) (Set a)

A hand-written definition of `length` would look like this:

    length (Foo m set) = length m + length set

This would produce an O(1) implementation of length, since Map and Set
are annotated with their lengths. But the default implementation of
length (which is what you get when you use `deriving Foldable`) would
instead produce

   length foo = foldl' (\acc _ -> acc + 1) 0 foo

which is O(n). Gross.

### What's the problem?

There's no problem deriving length for Foo. The trouble comes when
trying to derive length for a recursive type.

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

The most obvious implementation to derive would be

  length Nil = 0
  length (Cons _ xs) = 1 + length xs

but this is not tail recursive! That's absolutely no good. What we
*want* here is

  length = lengthPlus 0
  lengthPlus acc Nil = acc
  lengthPlus !acc (Cons _ xs) = lengthPlus (acc + 1) xs

We actually could arrange for that in this case, since we see that a
`List` contains itself recursively. But what about *mutual* recursion?

  data List2 a = Nil | Cons a (List2' a)
  newtype List2' a = List2' (List2 a)

Now the deriving mechanism can't see the recursion, and everything is horrible.

### The simplest solution

It seems likely that the simplest solution would be what nobody really
wants: add yet another method to Foldable:

  lengthPlus :: Int -> f a -> Int
  lengthPlus n xs = n + length xs

We could derive efficient implementations of `lengthPlus` without any
particular difficulty.

### Alternatives?

I haven't thought of any plausible alternatives yet. Maybe someone else will.

David


More information about the Libraries mailing list