Greg confessed on #london.pm to having written a `average` function in Perl in FP style… recursively.

I asked him about this, as a perfectly good average function (using `List::Util` would be:

sub avg { sum(@_) / @_ }

which is perfectly fine FP style too. As far as I could understand

it, he was reducing a tuple of sum and count. Though he said he wrote

it just-for-fun, it's not entirely unreasonable if you're using a

list-based language, where you'd otherwise have to traverse the list

twice (in Perl, arrays know how long they are).

Out of curiosity, I tried to check how Haskell defined `avg`, but it seems that it doesn't.

LoganCapaldo suggested the following definition:

>importData.List

> avg xs = sum xs / genericLength xs

We use `genericLength` because the normal `length`

function insists on returning an integer, while genericLength returns a

generic Number, which can be divided appropriately. (We'd otherwise

have to write `sum xs / (fromIntegral $ length xs)`)

The recursive function would work by summing a tuple, so that

avgs [1,3,5] => (9,3)

Once we have that we could divide the tuple using uncurry.

> avg' = uncurry (/) . avgs

As we're going to fold the number values into a tuple, we need a function like:

> sum_count s (t,c) = (t+s, c+1)

after which our definition is easily written as a fold

> avgs = foldr sum_count (0,0)

Which works just fine. But seeing the tuples, I thought of the comments from Joao and doserj, and thought of `(&&&)`.

>importControl.Arrow

> sum_count s = (+s).fst &&& succ.snd

And byorgey commented that the .fst and .snd pair can be abstracted away using `(***)`. So I tried

> sum_count s = (+s) *** succ

and was really rather surprised that it worked! Admittedly, the

definition is now something that scares me and whose intent is far less

clear than the first naive definition above:

> avg2 = uncurry (/) . foldr (\s -> (+s) *** succ) (0,0)

For extra bonus obfuscation points, making the lambda expression points-free is left as an exercise to the reader ;-)

**Update: **mauke pointed out that my Perl avg sub didn't work… added parens to sum (@_). Looks like naughty me didn't bother testing that code…