Lay González
Lay González

Reputation: 2985

Can you make an instance of a class not for a type but for a whole class in Haskell?

Suppose I want to make all numbers an instance of Monoid. Instead of having to create an instance for each Num like this:

instance Monoid Int where
  mappend = (+)
  mempty = 0

instance Monoid Float where
  mappend = (+)
  mempty = 0.0

-- etc

Is there something like this?

instance Num t => Monoid t where
  mappend = (+)
  mempty = 0

Edit

Some are answering with GHC extensions and warning about the potential issues; I found that informative, but I think I will stick with Sum, Product and whatever coerce does.

Upvotes: 8

Views: 191

Answers (2)

Michael Benfield
Michael Benfield

Reputation: 1374

I'm interpreting this as asking about a general premise, rather than specifically about Monoid and Num.

Maybe you could get what you wrote to work, by enabling language extensions FlexibleInstances, UndecidableInstances, and using overlapping instances.

But you probably wouldn't want to: it seems like instance Num t => Monoid t where ... is saying

"If t is an instance of Num, here's how to make t an instance of Monoid..."

Unfortunately, that's not right. What it's actually saying is more like

"Here's how to make t an instance of Monoid. First, it's necessary that t be an instance of Num. Next..."

Thus, if you write an instance declaration like this, you can't write any other instance declarations. (At least not without OverlappingInstances, which would bring its own issues.)

Upvotes: 21

yairchu
yairchu

Reputation: 24814

GHC allows your definition with some language extensions enabled

{-# LANGUAGE FlexibleInstances, UndecidableInstances #-}

instance Num t => Monoid t where
  mappend = (+)
  mempty = 0

This makes 2 <> 3 result in 5.

But this overlaps with other Monoid instances, so trying to evaluate "Hello" <> "World" results with an error: Overlapping instances for Monoid [Char]

So, I think that the short answer is: no.

Upvotes: 6

Related Questions