Max
Max

Reputation: 15955

Overriding the + operator for certain types

I have the following type definition:

data NumList n = NumList [Rational]

Then in my code I define some NumLists like so,

n1 = NumList [1, 2, 3]
n2 = NumList [4, 5, 6]

What I would like to do is this:

n3 = n1 + n2 -- Should be [5, 7, 9]

I tried defining this as so:

toList :: NumList n -> [Rational]
toList (NumList n) = n

(+) :: NumList -> NumList -> NumList
(+) x y = if length x == length y
          then
              zipWith (+) toList x toList y -- This probably isn't right, but I'll debug this later
          else
              error "NumLists must be same length to add"

The error I get is:

Ambiguous occurrence `+'
It could refer to either `NumList.+',
                             defined at NumList.hs:7:5
                          or `Prelude.+'

I don't see how this is ambiguous since Prelude.+ applies to the Num class and NumList.+ only applies to the NumList type. Any guidance on this? Also a little bonus question: Is there a way to use pattern matching to remove the if expression from the (+) function?

Upvotes: 0

Views: 116

Answers (1)

daniel gratzer
daniel gratzer

Reputation: 53871

The error right now is that there are 2 types of (+)s defined, one for Prelude and yours. You can fix this by making NumList an instance of the Num type.

instance Num NumList where
  (+) nl1 nl2 = implementPlus
  (*) nl1 nl2 = implementTimes
  (-) nl1 nl2 = implementMinus
  abs nl = NumList (map abs (toList nl))
  signum nl = NumList (map signum (toList nl))
  fromInteger i = NumList [fromInteger i]

Now addition will call implemenPlus and everything will be wonderful. As an added bonus, you can even write numeric literals, haskell will infer that they're a NumList and turn them into a list of one element, quite nice for writing lots of them.

Also, for your bonus question, I'd just write it like this

(NumList n1) + (NumList n2) = NumList $ zipWith (+) n1 n2

This is what I'd expect using it, that the result is the length of the shortest list. If you really want it to blow up,

 (NumList n1) + (NumList n2) |length n1 == length n2 =
                                NumList $ zipWith (+) n1 n2
                             | otherwise             = 
                                error "You done goofed"

This just uses guards, think of them as souped up ifs. And otherwise is simply defined as

otherwise = True

in prelude.

Upvotes: 2

Related Questions