LYAHFGG:
ある値は、その値が
Show型クラスのインスタンスになっていれば、文字列として表現できます。
Cats で Show に対応する型クラスは Show だ:
import cats._, cats.syntax.all._
3.show
// res0: String = "3"
"hello".show
// res1: String = "hello"
これが型クラスのコントラクトだ:
@typeclass trait Show[T] {
  def show(f: T): String
}
Scala には既に Any に toString があるため、Show
を定義するのは馬鹿げているように一見見えるかもしれない。
Any ということは逆に何でも該当してしまうので、型安全性を失うことになる。
toString は何らかの親クラスが書いたゴミかもしれない:
(new {}).toString
// res2: String = "repl.MdocSession1@b3c274f"
(new {}).show
// error: value show is not a member of AnyRef
// (new {}).show
//  ^^^^^^^^^^^^
object Show は Show のインスタンスを作成するための 2つの関数を提供する:
object Show {
  /** creates an instance of [[Show]] using the provided function */
  def show[A](f: A => String): Show[A] = new Show[A] {
    def show(a: A): String = f(a)
  }
  /** creates an instance of [[Show]] using object toString */
  def fromToString[A]: Show[A] = new Show[A] {
    def show(a: A): String = a.toString
  }
  implicit val catsContravariantForShow: Contravariant[Show] = new Contravariant[Show] {
    def contramap[A, B](fa: Show[A])(f: B => A): Show[B] =
      show[B](fa.show _ compose f)
  }
}
使ってみる:
case class Person(name: String)
case class Car(model: String)
{
  implicit val personShow = Show.show[Person](_.name)
  Person("Alice").show
}
// res4: String = "Alice"
{
  implicit val carShow = Show.fromToString[Car]
  Car("CR-V")
}
// res5: Car = Car(model = "CR-V")