Reputation: 2301
I'm playing with some Haskell code. I've defined two functions:
count :: [a] -> Int
count [] = 0
count (x:xs) = 1 + (count xs)
-- 03. Write a function that computes the mean of a list, i.e., the sum of all
-- elements in the list divided by its length. (You may need to use the
-- fromIntegralfunction to convert the length of the list from an integer
-- into a floating-point number.)
-- I've guessed this type definition, but it's incorrect:
-- listMean :: [a] -> Double
-- The following is the same inferred by hgci
listMean :: (Fractional a) => [a] -> a
listMean lst = (foldl1 (+) lst)/(fromIntegral (count lst))
Why [a] -> Double is not correct? It seems that I give lst that is a generic list of some type a and listMean returns a Double. What am I doing wrong?
Thanks, Alfredo
Upvotes: 2
Views: 309
Reputation: 36143
First of all, listMean :: [a] -> Double
says that listMean
is a function taking a list of any type a
to a single Double
value.
But you rely on being able to apply (+)
to the elements of the list (foldl1 (+)
), which requires that the type a
be an instance of Num
, which means you have at least:
listMean :: (Num a) => [a] -> b
You also apply (/)
to the value of type a
that results from the foldl1
operation. To do so, a
must not only be an instance of Num
, but of Fractional
. Applying this requirement to the type a
gives the type signature:
listMean :: (Fractional a) => [a] -> b
Now, what of b
? Well, the signature for (/)
is (/) :: (Fractional a) => a -> a -> a
. So, the result of listMean
must also be an instance of Fractional
. Further, it must be the same instance of Fractional
as that contained in the list: type b
is thus, in fact, type a
, and listMean
's most general signature is:
listMean :: (Fractional a) => [a] -> a
This is exactly what the compiler inferred. If you want to specialize this for Double
, you would have to replace both occurrences of a
with Double
:
listMean :: [Double] -> Double
This is because you have no operator in there that will coerce any instance of Fractional
into a Double
, so both input and output to (/)
must be of type Double
.
Upvotes: 20