6

I want to sum a zipped list.

averageGrade :: [Float] -> [Int] -> Float
averageGrade [0.75 , 0.25] [6, 4] , result: 0,75*6 + 0.25*4 = 5.5 

when I go to ghci and do the following:

sum(zipWith (*) [0.75, 0.25] [6, 4])

I get excactly what i want to.

But in code I'm getting an error, and I don't know why.

    averageGrade :: [Float] -> [Int] -> Float
    averageGrade a b
                | a == [] = 0
                | b == [] = 0
                | otherwise = (sum(zipWith (*) a b))

If I want to compile this I'm getting the following failure:

Couldn't match type ‘Int’ with ‘Float’
Expected type: [Float]
  Actual type: [Int]
In the third argument of ‘zipWith’, namely ‘b’
In the first argument of ‘sum’, namely ‘(zipWith (*) a b)’
Failed, modules loaded: none.
Sorun
  • 143
  • 5

3 Answers3

6

You can't * two numbers having a different type, like Float and Int. You need to explicitly convert one of them so that they have the same type (Float, in your case).

averageGrade :: [Float] -> [Int] -> Float
averageGrade a b
            | a == [] = 0
            | b == [] = 0
            | otherwise = sum (zipWith (\ x y -> x * fromIntegral y) a b)

Note that you do not really need to check the ==[] cases, since zipWith returns [] is those cases, and sum [] == 0.

averageGrade :: [Float] -> [Int] -> Float
averageGrade a b = sum (zipWith (\ x y -> x * fromIntegral y) a b)
chi
  • 111,837
  • 3
  • 133
  • 218
  • 2
    I think it's worth adding the reason why the `sum(zipWith (*) [0.75, 0.25] [6, 4])` worked in GHCi - namely that the integer literals `6` and `4` are polymorphic, and GHC is interpreting them as `Float`s (or probably `Double`s, not sure of the default) so the expression typechecks. The problem comes from the type signature, which means you're trying to give two different types to `(*)`. – Robin Zigmond Nov 14 '19 at 10:12
2

You can (*) different types given that those are members of Num type class. You may add Num and Eq constraints to the type signature such as;

averageGrade :: (Num a, Eq a) => [a] -> [a] -> a
averageGrade a b | a == [] = 0
                 | b == [] = 0
                 | otherwise = sum $ zipWith (*) a b

*Main> averageGrade [0.75 , 0.25] [6, 4]
5.5

However as @chi mentions you don't really need the checks for empty lists hence we don't really need the Eq constraint in the type signature. The following should be sufficient.

averageGrade :: Num a => [a] -> [a] -> a
averageGrade a b = sum $ zipWith (*) a b

*Main> averageGrade [0.75 , 0.25] [6, 4]
5.5
Redu
  • 25,060
  • 6
  • 56
  • 76
  • Even if the empty list check was necessary, you still don't need an `Eq` constraint. There are better ways to check if a list is empty, like the `null` function or direct pattern matching. – Robin Zigmond Nov 14 '19 at 10:09
  • @Robin Zigmond Yes right. My intention was to fix OP's snippet through the type signature. – Redu Nov 14 '19 at 10:40
1

Alternative implementation:

averageGrade :: [Float] -> [Float] -> Float
averageGrade [] _ = 0
averageGrade _ [] = 0
averageGrade (x:xs) (y:ys) = x * y + (averageGrade xs ys)

Usage:

averageGrade [1.0, 2.0] [2.0, 2.0]
Thomas Cook
  • 4,371
  • 2
  • 25
  • 42