Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

why does sum need GHC.Num.fromInteger?

Tags:

haskell

ghc

I have a 3d vector data type defined as 3 floats. I understand that if I provide a Num instance for my class and define the normal mathematical operators, I can use them on my class.

data Vec3 = Vec3 { x :: Float
                 , y :: Float
                 , z :: Float
                 } deriving (Show, Eq)

instance Num Vec3 where
  (+) v1 v2 = Vec3 (x v1 + x v2) (y v1 + y v2) (z v1 + z v2)

When I load my file into ghci, I get warnings because I didn't define all the functions in Num, which makes sense.

Prelude> :l temp.hs
[1 of 1] Compiling Main             ( temp.hs, interpreted )

temp.hs:6:10: Warning:
    No explicit method or default declaration for `*'
    In the instance declaration for `Num Vec3'

temp.hs:6:10: Warning:
    No explicit method or default declaration for `abs'
    In the instance declaration for `Num Vec3'

temp.hs:6:10: Warning:
    No explicit method or default declaration for `signum'
    In the instance declaration for `Num Vec3'

temp.hs:6:10: Warning:
    No explicit method or default declaration for `fromInteger'
    In the instance declaration for `Num Vec3'
Ok, modules loaded: Main.

However, I can still use the ones I've defined.

*Main> let a = Vec3 1.0 2.0 3.0
*Main> let b = Vec3 2.0 4.0 5.0
*Main> a + b
Vec3 {x = 3.0, y = 6.0, z = 8.0}

My confusion comes from the following error I get when trying to use the sum function

*Main> sum [a,b]
Vec3 {x = *** Exception: temp.hs:6:10-17: No instance nor default method for class operation GHC.Num.fromInteger

Why does sum need a fromInteger definition for my Vec3 data type? For one, I would have figured that sum only uses the + function, and for another, my data type doesn't use Integer.

like image 307
user3288829 Avatar asked Jul 12 '15 22:07

user3288829


People also ask

What is NUM Haskell?

Num is a typeclass — a group of types — which includes all types which are regarded as numbers. The (Num a) => part of the signature restricts a to number types – or, in Haskell terminology, instances of Num .

What is an instance in Haskell?

An instance of a class is an individual object which belongs to that class. In Haskell, the class system is (roughly speaking) a way to group similar types. (This is the reason we call them "type classes"). An instance of a class is an individual type which belongs to that class.


2 Answers

Here's how sum is implemented:

sum = foldl (+) 0

Notice the 0 literal. Let's check it's type in GHCi:

λ> :t 0
0 :: Num a => a

As it turns out, numeric literals are sugar for fromInteger. Ie, 0 is actually fromInteger 0.

Thus, sum requires fromInteger, because the above definition is sugar for:

sum = foldl (+) (fromInteger 0)

The implementation of fromInteger is easy:

instance Num Vec3 where
    fromInteger n = let a = (fromInteger n) in Vec3 a a a

Furthermore, I would highly recommend that, whenever making an instance, always define it completely to avoid unforeseen trouble like this.

like image 67
AJF Avatar answered Nov 03 '22 02:11

AJF


What should sum [] :: Vec3 return?


The sum function could be defined as

sum :: (Num a) => [a] -> a
sum =  foldl (+) 0

The 0 there is actually fromInteger (0 :: Integer), thus you need fromInteger to use sum.

Actually in base-4.8 sum is defined in terms of Sum Monoid and Foldable, but that's different story. You still need fromInteger (0 :: Integer) there.

like image 23
phadej Avatar answered Nov 03 '22 02:11

phadej