Skip to content

Instantly share code, notes, and snippets.

@xmeng1
Created June 18, 2019 05:02
Show Gist options
  • Save xmeng1/851522ba5b83450ed00114c3d58a60ae to your computer and use it in GitHub Desktop.
Save xmeng1/851522ba5b83450ed00114c3d58a60ae to your computer and use it in GitHub Desktop.
Cats Type Class Demo
// Define a very simple JSON AST
sealed trait Json
final case class JsObject(get: Map[String, Json]) extends Json
final case class JsString(get: String) extends Json
final case class JsNumber(get: Double) extends Json
case object JsNull extends Json
////////////////// Step 1
// The "serialize to JSON" behaviour is encoded in this trait
trait JsonWriter[A] {
def write(value: A): Json
}
final case class Person(name: String, email: String)
////////////////// Step 2
// any definitions marked implicit in Scala MUST BE placed inside an object or trait
object JsonWriterInstances {
implicit val stringWriter: JsonWriter[String] =
(value: String) => JsString(value)
implicit val personWriter: JsonWriter[Person] =
(value: Person) =>
JsObject(
Map("name" -> JsString(value.name), "email" -> JsString(value.email))
)
// etc...
}
////////////////// Step 3 - 1
object Json {
def toJson[A](value: A)(implicit w: JsonWriter[A]): Json =
w.write(value)
}
////////////////// Step 3 - 2
object JsonSyntax {
implicit class JsonWriterOps[A](value: A) {
def toJson(implicit w: JsonWriter[A]): Json =
w.write(value)
}
}
////////////////// Usage
object Main extends App {
import JsonWriterInstances._
Json.toJson(Person("Dave", "dave@example.com"))
import JsonWriterInstances._
import JsonSyntax._
Person("Dave", "dave@example.com").toJson
}
////////////////// Cats Show Usage
final case class Cat(name: String, age: Int, color: String)
object CatShowMain extends App {
implicit val catShow = Show.show[Cat] { cat =>
import cats.instances.int._ // for Show
import cats.instances.string._ // for Show
val name = cat.name.show
val age = cat.age.show
val color = cat.color.show
s"$name is a $age year-old $color cat."
}
println(Cat("Garfield", 38, "ginger and black").show)
println(Cat("Garfield", 38, "ginger and black").show)
}
////////////////// Cats Show Source code
// 1
trait Show[T] extends Show.ContravariantShow[T]
trait ContravariantShow[-T] extends Serializable {
def show(t: T): String
}
// 2 (default, and need to define the customized class type instance)
trait StringInstances extends cats.kernel.instances.StringInstances {
implicit val catsStdShowForString: Show[String] =
Show.fromToString[String]
}
// 3
trait Ops[A] {
def typeClassInstance: Show[A]
def self: A
def show: String = typeClassInstance.show(self)
}
trait ToShowOps {
implicit def toShow[A](target: A)(implicit tc: Show[A]): Ops[A] = new Ops[A] {
val self = target
val typeClassInstance = tc
}
}
trait ShowSyntax extends Show.ToShowOps {
implicit final def showInterpolator(sc: StringContext): Show.ShowInterpolator = Show.ShowInterpolator(sc)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment