Created
June 18, 2019 05:02
-
-
Save xmeng1/851522ba5b83450ed00114c3d58a60ae to your computer and use it in GitHub Desktop.
Cats Type Class Demo
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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