title: Creating Monoids for every subclass using Scalaz (or Shapeless)
body: <p>Is it possible to create monoids for every sub-class? For example, </p>
  
  <pre><code>package currency 
  
  final case class GBP[A: Monoid](amount: A)
  
  object Implicits {
    implicit class CurrencyOps[A: Monoid](a: A) {
      def GBP = currency.GBP(a)
    }
  
    implicit def gbpMonoid[A: Monoid]: Monoid[GBP[A]] = new Monoid[GBP[A]] {
      override def zero =
        GBP(Monoid[A].zero)
  
      override def append(f1: GBP[A], f2: =&gt; GBP[A]): GBP[A] =
        GBP(Semigroup[A].append(f1.amount, f2.amount))
    }
  }
  
  test("GBP support plus") {
    1.GBP |+| 2.GBP shouldBe 3.GBP // passed
  }
  </code></pre>
  
  <p>I would like to add more case classes representing <em>currency</em> (e.g <code>USD</code>, <code>EUR</code>, ..)</p>
  
  <pre><code>sealed trait Currency
  final case class GBP[A: Monoid](amount: A) extends Currency
  final case class USD[A: Monoid](amount: A) extends Currency
  final case class EUR[A: Monoid](amount: A) extends Currency
  </code></pre>
  
  <p>As a result, I have to implement monoids for new case classes. It's somewhat boilerplate.</p>
  
  <pre><code>implicit class CurrencyOps[A: Monoid](a: A) {
    def GBP = currency.GBP(a)
    def EUR = currency.EUR(a)
    def USD = currency.USD(a)
  }
  
  implicit def gbpMonoid[A: Monoid]: Monoid[GBP[A]] = new Monoid[GBP[A]] {
    override def zero =
      GBP(Monoid[A].zero)
  
    override def append(f1: GBP[A], f2: =&gt; GBP[A]): GBP[A] =
      GBP(Semigroup[A].append(f1.amount, f2.amount))
  }
  
  implicit def usdMonoid[A: Monoid]: Monoid[USD[A]] = new Monoid[USD[A]] {
    override def zero =
      USD(Monoid[A].zero)
  
    override def append(f1: USD[A], f2: =&gt; USD[A]): USD[A] =
      USD(Semigroup[A].append(f1.amount, f2.amount))
  }
  
  implicit def eurMonoid[A: Monoid]: Monoid[EUR[A]] = new Monoid[EUR[A]] {
    override def zero =
      EUR(Monoid[A].zero)
  
    override def append(f1: EUR[A], f2: =&gt; EUR[A]): EUR[A] =
      EUR(Semigroup[A].append(f1.amount, f2.amount))
  }
  </code></pre>