Can you overload + in haskell?

While I've seen all kinds of weird things in Haskell sample code - I've never seen an operator plus being overloaded. Is there something special about it?

Let's say I have a type like Pair, and I want to have something like

 Pair(2,4) + Pair(1,2) = Pair(3,6)

Can one do it in haskell?

I am just curious, as I know it's possible in Scala in a rather elegant way.


Yes

(+) is part of the Num typeclass, and everyone seems to feel you can't define (*) etc for your type, but I strongly disagree.

newtype Pair a b = Pair (a,b)  deriving (Eq,Show) 

I think Pair a b would be nicer, or we could even just use the type (a,b) directly, but...

This is very much like the cartesian product of two Monoids, groups, rings or whatever in maths, and there's a standard way of defining a numeric structure on it, which would be sensible to use.

instance (Num a,Num b) => Num (Pair a b) where
   Pair (a,b) + Pair (c,d) = Pair (a+c,b+d)
   Pair (a,b) * Pair (c,d) = Pair (a*c,b*d)
   Pair (a,b) - Pair (c,d) = Pair (a-c,b-d)
   abs    (Pair (a,b)) = Pair (abs a,    abs b) 
   signum (Pair (a,b)) = Pair (signum a, signum b) 
   fromInteger i = Pair (fromInteger i, fromInteger i)

Now we've overloaded (+) in an obvious way, but also gone the whole hog and overloaded (*) and all the other Num functions in the same, obvious, familiar way mathematics does it for a pair. I just don't see the problem with this. In fact I think it's good practice.

*Main> Pair (3,4.0) + Pair (7, 10.5)
Pair (10,14.5)
*Main> Pair (3,4.0) + 1    -- *
Pair (4,5.0)

* - Notice that fromInteger is applied to numeric literals like 1, so this was interpreted in that context as Pair (1,1.0) :: Pair Integer Double. This is also quite nice and handy.


Overloading in Haskell is only available using type classes. In this case, (+) belongs to the Num type class, so you would have to provide a Num instance for your type.

However, Num also contains other functions, and a well-behaved instance should implement all of them in a consistent way, which in general will not make sense unless your type represents some kind of number.

So unless that is the case, I would recommend defining a new operator instead. For example,

data Pair a b = Pair a b
    deriving Show

infixl 6 |+| -- optional; set same precedence and associativity as +
Pair a b |+| Pair c d = Pair (a+c) (b+d)

You can then use it like any other operator:

> Pair 2 4 |+| Pair 1 2
Pair 3 6