-2

Say I wanted to take the average of a list of floating point values, then at some point i need to use "sum" and "length" (built in functions). Can you make a function that calculates the average of arbitrary length list of Floating point values?

JJ chips
  • 97
  • 5
  • 1
    "Yes"? After all, you can just write your own `length` and `sum`. Note that the combination of `sum` and `length` usually leads to problems, though. – Zeta Mar 29 '16 at 12:27
  • Why would i get problems? – JJ chips Mar 29 '16 at 12:35
  • because `length` returns usually an `Int` and you will get trouble if you try to divide a `Float` (the sum) by said `Int` – Random Dev Mar 29 '16 at 12:42
  • 1
    @Carsten: I'm thinking more in terms of `average [1..10^10]`. See RWH's chapter on profiling. – Zeta Mar 29 '16 at 12:50
  • 1
    I'm voting to close this question as off-topic because it's an assignment, not a programming question. – dfeuer Mar 29 '16 at 18:20

2 Answers2

1

You could use foldl' to build up a tuple that includes both the running count of items as well as the running sum, then divide to get the average.

data StrictPair a b = StrictPair !a !b

myAvg :: Fractional a => [a] -> a
myAvg [] = error "Empty list"
myAvg list =
  let
    tupleSum (StrictPair count sum) x = StrictPair (count + 1) (sum + x)
    StrictPair totalCount totalSum = foldl' tupleSum (StrictPair 0 0) list
  in
    totalSum / totalCount

The use of foldl' and StrictPair force evaluation to avoid memory issues. (thanks for the recommendation, @Jubobs, @Zeta, and @dfeuer!)

Chad Gilbert
  • 36,115
  • 4
  • 89
  • 97
  • 2
    Too many thunks :p A left fold, with forced evaluation of the intermediate values, would make more sense, here, in my opinion. Richard Bird shows how to do exactly that in chapter 7 of his book *Thinking functionally with Haskell*. – jub0bs Mar 29 '16 at 12:45
  • @Jubobs is Bird's approach equivalent to `data Pair a b = Pair !a !b` together with `foldl'`? – Zeta Mar 29 '16 at 12:52
  • @Zeta Essentially, yes. – jub0bs Mar 29 '16 at 14:45
  • 1
    The current code still isn't strict enough. You force the pairs, but not their components. – dfeuer Mar 29 '16 at 19:41
  • @ChadGilbert What dfeuer means is that `foldl'` doesn't force the evaluation of the elements of the pair (because the pair is already in [weak head normal form](http://stackoverflow.com/questions/6872898/haskell-what-is-weak-head-normal-form)). You need to either use a ["strict pair" type](https://hackage.haskell.org/package/strict-0.3.2/docs/Data-Strict-Tuple.html) for the accumulator, or use `seq` to force evaluation explicitly. – jub0bs Mar 30 '16 at 12:22
  • Thanks for the clarification on that, @Jubobs, it makes much more sense now. – Chad Gilbert Mar 30 '16 at 12:51
1

No, this is essentially impossible in general. Addition and division are necessary to calculate the mean of a list of numbers. The functions to calculate these for standard types like Rational are "built in".

dfeuer
  • 48,079
  • 5
  • 63
  • 167