Reputation: 595
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
Upvotes: 1
Views: 206
Reputation: 5315
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
}
Upvotes: 4