Skip to content

Instantly share code, notes, and snippets.

@JoolsF
Last active April 11, 2018 21:35
Show Gist options
  • Select an option

  • Save JoolsF/61fcaf2cdf1e7054ddfbdd94142a1b74 to your computer and use it in GitHub Desktop.

Select an option

Save JoolsF/61fcaf2cdf1e7054ddfbdd94142a1b74 to your computer and use it in GitHub Desktop.
Type class example 2
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
// 1 the type class
trait JsonWriter[A] {
def write(value: A): Json
}
final case class Person(name: String, email: String)
// 2 type class instances
object JsonWriter {
implicit val personWriter: JsonWriter[Person] =
new JsonWriter[Person] {
override def write(value: Person): Json = JsObject(Map(
"name" -> JsString(value.name),
"email" -> JsString(value.email)
))
}
implicit def optionWriter[A](implicit writer: JsonWriter[A]): JsonWriter[Option[A]] =
new JsonWriter[Option[A]] {
def write(value: Option[A]): Json = value match {
case Some(a) => writer.write(a)
case None => JsNull
}
}
}
object Json {
// 3 type class interface
def toJson[A](value: A)(implicit w: JsonWriter[A]) =
w.write(value)
}
// 4 Interface syntax - extend existing types with interface methods
object JsonSyntax {
implicit class JsonWriterOps[A](value: A) {
def toJson(implicit w: JsonWriter[A]): Json =
w.write(value)
}
}
object Main extends App {
import Json._
val p = Person("julian", "foo@bar.com")
println(toJson(p)) // JsObject(Map(name -> JsString(julian), email -> JsString(foo@bar.com)))
import JsonSyntax._
println(p.toJson) // same result as above but much nicer syntax as it extends the existing type
val pOpt: Option[Person] = Some(p)
println(pOpt.toJson) //same as above, uses OptionWriter instance
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment