1
votes

I am trying to understand typeclasses and so far i got to Monoids, which are simple enough:

object AbstractAlgebra {
  case class Pair[A,B](a: A, b: B)

  trait Monoid[T] {
    def times(t1: T, t2: T): T
    def unit: T
  }
  object Monoid {
    implicit object MonoidIntPlus extends Monoid[Int] {
      def times(i1: Int, i2: Int) = i1 + i2
      def unit = 0
    }
    implicit object StringMonoid extends Monoid[String] {
      def times(s1: String, s2: String) = s1 + s2
      def unit = ""
    }

    implicit object PairOfMonoids extends Monoid[Pair[Monoid, Monoid]] = ???
  }
}

I suppose my problem is the type Monoid[Pair[Monoid, Monoid]], cause I'm not really dealing with two monoid instances, only two classes that are implicit monoids, but I am not sure how to express that.

Any help or references would be appreciated

1

1 Answers

4
votes

Monoid is not a type in itself. It's a type constructor, so Pair[Monoid, Monoid] makes no sense.

What you really want is actually the following: assuming that you have a Monoid type class instance for two given types A and B, then make an instance also for Pair[A, B].

This can be written as follows (the implementation is the most natural one you can derive):

implicit def monoidPair[A, B](implicit A: Monoid[A], B: Monoid[B]): Monoid[Pair[A, B]] = new Monoid[Pair[A, B]] {
  def times(p1: Pair[A, B], p2: Pair[A, B]) =
    Pair(A.times(p1.a, p2.a), B.times(p1.b, p2.b))
  def unit = Pair(A.unit, B.unit)
}

This will do exactly what I explained before: If implicit instances for types Monoid[A] and Monoid[B] are found, then it puts a new implicit instance of type Monoid[Pair[A, B]] in scope.

Note. Your case class Pair[A, B] is already defined in Predef (although it's been deprecated since 2.11.0) as Tuple2[A, B] or (A, B).

Other note. If you don't like defining implicit instances as def or val, you can do the same with an implicit class:

implicit class MonoidPair[A, B](implicit A: Monoid[A], B: Monoid[B]) extends Monoid[Pair[A, B]] {
  ... //same body as before
}