I wanted to make a simple average (mean) function in Haskell, so I tried the following in ghci:
ghci> let avg xs = (sum xs) / (length xs)
And it throws the following error:
No instance for (Fractional Int)
arising from a use of `/'
Possible fix: add an instance declaration for (Fractional Int)
In the expression: (sum xs) / (length xs)
In an equation for `avg': avg xs = (sum xs) / (length xs)
So, I decided to break it down by trying the following:
ghci> let a = (sum [1,2])
ghci> let b = (length [1,2])
That all works good.
So then I tried the following
ghci> a/b
And I got the following error:
Couldn't match expected type `Integer' with actual type `Int'
In the second argument of `(/)', namely `b'
In the expression: a / b
In an equation for `it': it = a / b
So, in Haskell are Integer and Int different? – And if so, how can I make the original function work?
The problem is that
but
So, when you say
whatever / length xs, it doesn’t type, because Int is not a Fractional number type! This is what the “No instance for…” error is trying to tell you. This definition will work:Here, we use
fromIntegral :: (Integral a, Num b) => a -> bto convert the Int we get fromlengthinto a Fractional number. Note that the resulting function will only work on lists of Fractional numbers because of this (but e.g.avg [1,2,3]will still work fine).To explain the error you get when doing it “in pieces”, it’s because in
let a = sum [1,2], the list’s elements are Integers, so their sum is an Integer, but inlet b = length [1,2], the resulting length is an Int, per the type oflengthI showed above. So, when you doa/b, this fails way before it even realises that Int and Integer are not instances of Fractional — since(/)takes two arguments of the same type, it can’t possibly work.And yes, Integer and Int are different — Int is a fixed-precision integral type, usually the size of a numeric word, like
longin C, whereas Integer is an arbitrary-precision bignum, capable of storing any integer; or at least, any integer that’ll fit into your RAM 🙂Another possible approach would be to define
avg xsassum xs / genericLength xs, usingData.List.genericLength, which works with any numeric type, not just Ints:For that, you’ll have to
import Data.Listin GHCi. Yet another possible approach (but one resulting in a different function altogether) would be to use integer division:let avg xs = sum xs `div` length xs(note:a `div` bis justdiv a b; this syntactic sugar works for every function).