0

I have the below simple program to find the average of a list. I know my error is related to the inference of types but I cannot correct it. Can I get a correction and a simple explanation for this?

average :: Float
average= uncurry (/) . sumlen

sumlen ::[Int]-> (Int,Int)
sumlen = foldl f (0,0)
         where f (s,n) x = (s+x,n+1)

The error is:

  • Couldn't match expected type ‘Float’
                      with actual type ‘[Int] -> Int’
   • Probable cause: ‘(.)’ is applied to too few arguments
          In the expression: uncurry (/) . sumlen
          In an equation for ‘average’: average = uncurry (/) . sumlen
Gakuo
  • 845
  • 6
  • 26
  • The average of which list are you trying to find? Do you maybe want `average` to be a function, not a `Float`? – sepp2k Nov 26 '18 at 10:47
  • 1
    firstly: `average` is not a `Float`. It is a function `[Int] -> Float`. Also, you should explictly convert your `Int`s into `Float` when applying `(/)` – lsmor Nov 26 '18 at 10:49
  • Possible duplicate of [Haskell types frustrating a simple 'average' function](https://stackoverflow.com/questions/2376981/haskell-types-frustrating-a-simple-average-function) – Redu Nov 26 '18 at 14:31

1 Answers1

3

Summary: Haskell is a strongly typed language.

You force the type of sumlen to be [Int] -> (Int,Int).

The type of (/) is Fractional a => a -> a -> a.

Let us typecheck your function. First we will try to infer its type:

average = (uncurry (/)) . sumlen 
uncurry :: (a -> b -> c) -> (a,b) -> c
(/) :: Fractional d => d -> d -> d
(.) :: (f -> g) -> (e -> f) -> e -> g
sumlen :: [Int] -> (Int,Int)
So:
e = [Int]
f = (Int,Int) = (a,b) = (d,d)
g = d = Int
average :: Fractional Int => [Int] -> Int

Now you tell Haskell that average :: Float and Haskell tells you that a float is not a function. This is your error.

If you remove the annotation then you will be told that there is no instance Fractional Int. This is because you can’t represent or reasonably approximate 1 / 2 as an Int.

How to fix this?

Step 0 is to not write down a type signature that is wrong (ie average :: Float)

One thing you could do is have a more general sumlen. Try Num a => [a] -> (a,a) instead. You could even have (Num a, Num b) => [a] -> (a,b). Then you can have the sensible type average :: Fractional a => [a] -> a

Another thing you could do is convert from integers:

average xs = fromIntegral s / fromIntegral l where
  (s,l) = sumlen xs
Dan Robertson
  • 4,315
  • 12
  • 17