foobar
foobar

Reputation: 5108

Inferring type class from operator

If I use the + operator, Haskell automatically infers the type class Num:

> let add x y = x + y
> :t add
add :: Num a => a -> a -> a

Does this mean I cannot have multiple type classes with a + operator?

Upvotes: 3

Views: 203

Answers (4)

gatoatigrado
gatoatigrado

Reputation: 16850

You can have multiple type classes with the + operator, it's just that the Num class implementation is imported implicitly via the Prelude. Either add the language extension

{-# LANGUAGE NoImplicitPrelude #-}

or add a line

import Prelude hiding ((+))

If you want a + that includes two type classes, say Num and A, then you could create a new typeclass that encapsulates both,

import Prelude hiding (id, (.), (+))
import qualified Prelude
import qualified A

class GeneralPlus a where (+) :: a -> a -> a
instance Num a => GeneralPlus a where (+) = (Prelude.+)
instance A a => GeneralPlus a where (+) = (A.+)

Upvotes: 0

ertes
ertes

Reputation: 2297

I think the question is whether it's possible to have multi-class operators. This sounds like a misunderstanding of how type classes work. You may want to search for the type families extension, if you want to implement something like vector spaces, where the arguments have different types:

(.*) :: VectorSpace v => Scalar v -> v -> v

For a library using this approach see the vector-space package.

Upvotes: 0

Note that + is not so much an operator as it is a function which defaults to infix positioning. This means that it obeys the same kind of scoping rules as all other functions, and the same behaviour with typeclasses.

Specifically, a typeclass defines a number of functions that are polymorphic across all types that instantiate that particular typeclass. So given the definition of Num as:

class (Eq a, Show a) => Num a where
  (+) :: a -> a -> a
  (*) :: a -> a -> a
  (-) :: a -> a -> a
  negate :: a -> a
  abs :: a -> a
  signum :: a -> a
  fromInteger :: Integer -> a

we can conclude that anything that includes a definition of Num in its scope — such as anything importing Prelude without qualification or exclusion of Num — will already have a definition in scope for the function (+); which is an ordinary function with type signature a -> a -> a, and a syntactic sugar tendency to be assumed infix, so that you'd write x + y instead of + x y.

In particular, all of this means that just as you can't have fmap be a function defined both by the typeclass Functor and by some other typeclass, you also can't have + be defined both by Num and by some other typeclass.

If you do want to define it elsewhere, you can always import the corresponding module qualified — however, the non-alphabetic function names that default to infix also end up really clumsy when you import them qualified. You'd end up writing things like 3 M.+ 4 instead of 3+4.

Upvotes: 3

sepp2k
sepp2k

Reputation: 370162

You can't have multiple type classes defining + in the same module (the same applies to any other function name of course - not just +).

And if you import multiple modules which define + (whether it be as part of a typeclass or not), you either need to hide + when importing all but one of them, import all but one of them as qualified or always refer to + qualified.

Upvotes: 9

Related Questions