1. Show

Show 

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 には既に AnytoString があるため、Show を定義するのは馬鹿げているように一見見えるかもしれない。 Any ということは逆に何でも該当してしまうので、型安全性を失うことになる。 toString は何らかの親クラスが書いたゴミかもしれない:

(new {}).toString
// res2: String = "repl.MdocSession1@b3c274f"
(new {}).show
// error: value show is not a member of AnyRef
// (new {}).show
//  ^^^^^^^^^^^^

object ShowShow のインスタンスを作成するための 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")