3

I want a function that calculates average mark from a given list of marks. This is what I have made so far:

getAverageRate :: [Int]->Int
getAverageRate marks = (fromIntegral (foldr (+) 0 marks))/(fromIntegral (length marks))

What I am trying to do is to get the sum of all marks in the list by using 'foldr' then divide by 'length marks'. Despite I already use 'fromIntegral' this error still appears and I can not find the problem.

No instance for (Fractional Int) arising from a use of `/'
Possible fix: add an instance declaration for (Fractional Int)
In the expression:
  (fromIntegral (foldr (+) 0 marks)) / (fromIntegral (length marks))
In an equation for `getAverageRate':
    getAverageRate marks
      = (fromIntegral (foldr (+) 0 marks))
        / (fromIntegral (length marks))
Bao Long Ngo
  • 67
  • 1
  • 4
  • By calling `fromIntegral`, you're asking for a conversion from `Int` to some other type. But by restricting the return type of your function to `Int`, the type you're painstakingly converting those `Int`s to is... `Int`! – Daniel Wagner Feb 26 '14 at 04:32

1 Answers1

8

The thing is that Int represents an integer, so it doesn't make sense to be able to divide it since most divisions result in things which aren't integers.

Happily we have div, which is integer division, so you could do

 average :: [Int] -> Int
 average [] = error "Can't average an empty list"
 average xs = sum xs `div` length xs

If you don't want to use integer division, then we could do something like

 average :: [Int] -> Double
 average xs = fromIntegral (sum xs) / fromIntegral (length xs)

which just promotes everything to a Double for division.

Finally you could choose a method for rounding and go with what you have

 average xs = round $ fromIntegral (sum xs) / fromIntegral (length xs)

(Friendly neighborhood warning that sum is evil and uses foldl instead of foldl' so be sure to compile with -O2 when using long lists)

daniel gratzer
  • 52,833
  • 11
  • 94
  • 134
  • 1
    As someone who is new to haskell, why is `sum` evil? – devshorts Feb 26 '14 at 01:25
  • 3
    @devshorts it's based on `foldl` which can stackoverflow in situations you wouldn't expect. It works with `-O2` though search foldl vs foldl' – daniel gratzer Feb 26 '14 at 01:27
  • Excuse my self plugging here, but for Haskell beginners here's a description of why `foldl'` is better than `foldl`. – J. Abrahamson Feb 26 '14 at 04:15
  • 2
    @J.Abrahamson I think you forgot a link? I'd actually love a good tutorial to point to so please share :) – daniel gratzer Feb 26 '14 at 04:21
  • 2
    Oh, I did: http://stackoverflow.com/questions/20356742/foldr-foldl-haskell-explanation/20359256#20359256 Thanks for notifying me – J. Abrahamson Feb 26 '14 at 04:52
  • I'd also add that for unsigned integers it's better to use `quot` and `rem` rather than `div` and `mod` – they are slightly faster due to the different approach to sign processing. – Yuuri Feb 26 '14 at 06:06