LYAHFGG:
Members of
Show
can be presented as strings.
Cats’ equivalent for the Show
typeclass is Show
:
import cats._, cats.syntax.all._
3.show
// res0: String = "3"
"hello".show
// res1: String = "hello"
Here’s the typeclass contract:
@typeclass trait Show[T] {
def show(f: T): String
}
At first, it might seem silly to define Show
because Scala
already has toString
on Any
.
Any
also means anything would match the criteria, so you lose type safety.
The toString
could be junk supplied by some parent class:
(new {}).toString
// res2: String = "repl.MdocSession1@891c355"
(new {}).show
// error: value show is not a member of AnyRef
// (new {}).show
// ^^^^^^^^^^^^
object Show
provides two functions to create a Show
instance:
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)
}
}
Let’s try using them:
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")