Reputation: 101
I'm new to Haskell so this could be a stupid question. I'm reading a book where it says :type sum
is supposed to show sum :: (Num a) => [a] -> a
. Instead of that the message is sum :: (Num a, Foldable t) => t a -> a
. As I've seen in https://www.haskell.org/hoogle/?hoogle=Sum this difference is due to -I think- the existence of two different sum functions. Maybe it's something like polymorphism in Java, I'm just starting and I have no idea about how Haskell works.
So my questions are: how could I use the sum function which type is sum :: (Num a) => [a] -> a
instead of the other one? Could you explain me what's going on here?
Upvotes: 1
Views: 1361
Reputation: 34398
As I've seen in https://www.haskell.org/hoogle/?hoogle=Sum this difference is due to -I think- the existence of two different sum functions. Maybe it's something like polymorphism in Java
It is, indeed, polymorphism, though not in this way (see the P.S. at the end of this answer). Note that...
sum :: (Num a) => [a] -> a
... is already polymorphic in the type of the numbers being summed, so it would work with, for instance, lists of Integer
and lists of Double
. The difference between that and...
sum :: (Num a, Foldable t) => t a -> a
... is that this sum
is also polymorphic in the type of the container:
GHCi> -- +t makes GHCi print the types automatically.
GHCi> :set +t
GHCi> sum [1 :: Integer, 2, 3]
6
it :: Integer
GHCi> sum [1 :: Double, 2, 3]
6.0
it :: Double
GHCi> import qualified Data.Set as S
GHCi> :t S.fromList
S.fromList :: Ord a => [a] -> S.Set a
GHCi> sum (S.fromList [1 :: Double, 2, 3])
6.0
it :: Double
For a container type to be used with sum
, it has to have an instance of the Foldable
class, which covers functions that, like sum
, might be expressed as flattening the container into a list and then folding it in some way.
P.S.: Your book says something different than what you have seen because until quite recently the sum
function in the Prelude used to have the less general, list-specific type, and your book predates the change. Having two different functions called sum
, even if one is strictly more general than the other, would lead to a name clash (it was for a similar reason that I imported the Data.Set
module qualified in the example above -- it is a good idea to do so because it defines a few functions such as map
that clash with Prelude functions, and qualifying them with, say, S.map
avoids any issues).
Upvotes: 2