Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does Haskell differentiate between difference possible type class instances

Apologies if I am using the wrong name for things. My question comes from contrasting Scala and Haskell syntax. Consider:

class Monoid a where
  mempty :: a
  mappend :: a -> a -> a

instance Monoid Int where 
  mempty = 0
  mappend a b = a + b

sigma :: (Monoid a) => Int -> Int -> (Int -> Int) -> (Int -> a) -> a
sigma a b inc comp =
  if a > b then mempty else mappend (comp a) (sigma (inc a) b inc comp)

In Scala it would probably be something like:

trait Monoid[A] {
  def mempty: A
  def mappend(a1: A, a2: A): A
}

class IntMonoid extends Monoid[Int] {
  def mempty = 0
  def mappend(a: Int, b: Int) = a + b
}

def sigma[A](a: Int, b: Int, inc: Int => Int, comp: Int => a)
            (implicit m: Monoid[A]): A =
  if (a > b) m.mempty else m.append(comp(a), sigma(inc(a), b, inc, comp))

Now, Int can be a Monoid with 0 and addition, but also with 1 and multiplication, so we can provide 2 type classes, one for each implementation. In Scala, if both implementations are implicit within the scope and have the same priority, this will cause a compile error. We can simple manually pass the correct instance in this case, and the error will be resolved.

What is the Haskell equivalent for this situation? If there are two instances of Int being Monoid, how can one choose which implementation to use?

like image 711
Henry Henrinson Avatar asked Dec 04 '22 06:12

Henry Henrinson


1 Answers

Haskell simply has two newtype wrapper for any type that actually is an instance of Num (includes Int type) typeclass: Sum and Product. So, Sum is a monoid under addition and Product type is a monoid under multiplication. Taken from actual source:

newtype Sum a = Sum { getSum :: a }
        deriving (Eq, Ord, Read, Show, Bounded, Generic, Generic1, Num)

instance Num a => Monoid (Sum a) where
        mempty = Sum 0
        Sum x `mappend` Sum y = Sum (x + y)

newtype Product a = Product { getProduct :: a }
        deriving (Eq, Ord, Read, Show, Bounded, Generic, Generic1, Num)

instance Num a => Monoid (Product a) where
        mempty = Product 1
        Product x `mappend` Product y = Product (x * y)
like image 121
Sibi Avatar answered Dec 06 '22 18:12

Sibi