ProductTypeClass

trait Show[T] {
  def show(t: T): String
}

object Show extends ProductTypeClassCompanion[Show] {

  def apply[T](implicit T: Show[T]) = T

  def from[T](f: T => String): Show[T] = new Show[T] {
    def show(t: T): String = f(t)
  }

  implicit val string = from[String](_.reverse)
  implicit val int = from[Int](Integer.toHexString)

  object typeClass extends ProductTypeClass[Show] {
    override def product[H, T <: HList](ch: Show[H], ct: Show[T]): Show[::[H, T]] = from(ht =>
      ch.show(ht.head) + " " + ct.show(ht.tail)
    )

    override def emptyProduct: Show[HNil] = from(_ => "")

    override def project[F, G](instance: => Show[G], to: (F) => G, from: (G) => F): Show[F] =
      Show.from((f: F) => instance.show(to(f)))
  }
}

case class Example(name: String, value: Int)

Show[Example].show(Example("Me", 12))  // returns "eM c"