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")