Skip to content

Instantly share code, notes, and snippets.

@drstevens
Created February 26, 2014 21:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save drstevens/9238955 to your computer and use it in GitHub Desktop.
Save drstevens/9238955 to your computer and use it in GitHub Desktop.
Applicative for play.api.libs.json.JsResult
Welcome to Scala version 2.10.2 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_25).
Type in expressions to have them evaluated.
Type :help for more information.
scala> import play.api.libs.json._; import play.api.libs.functional.Applicative;
import play.api.libs.json._
import play.api.libs.functional.Applicative
scala> val expected = JsSuccess(10, JsPath(List(KeyPathNode("somekey"))))
expected: play.api.libs.json.JsSuccess[Int] = JsSuccess(10,/somekey)
scala> val actual = implicitly[Applicative[JsResult]].apply(implicitly[Applicative[JsResult]].pure(identity[Int] _), expected)
actual: play.api.libs.json.JsResult[Int] = JsSuccess(10,)
scala> actual == expected
res0: Boolean = false
import play.api.libs.json._
import play.api.libs.functional.Applicative
sealed trait Node {
def i: Int
def j: String
}
object Node {
private val jsApplicative = implicitly[Applicative[JsResult]]
val writes: Writes[Node] = Writes { node =>
val others = node match {
case a: A => Nil
case b: B => List("k" -> JsNumber(b.k))
case c: C => List("l" -> JsNumber(c.l))
}
JsObject("i" -> JsNumber(node.i) :: "j" -> JsString(node.j) :: others)
}
val reads: Reads[Node] = Reads { json =>
val iResult = (json \ "i").validate[Int]
val jResult = (json \ "j").validate[String]
val result: JsResult[(Int, String) => Node] =
json \ "k" match {
case _: JsUndefined =>
json \ "l" match {
case _: JsUndefined => JsSuccess(A(_, _))
case lJS => lJS.validate[Long] map (l => C.apply(_, _, l))
}
case kJS => kJS.validate[Long] map (k => B.apply(_, _, k))
}
jsApplicative.apply[String, Node](jsApplicative.apply[Int, String => Node](result.map(_.curried), iResult), jResult)
}
val betterReads: Reads[Node] = Reads { json =>
import PlayIntegration.applicativeAsScalazApplicative
import scalaz.{Applicative => ZApplicative}
ZApplicative[JsResult].ap2(
(json \ "i").validate[Int],
(json \ "j").validate[String]) {
json \ "k" match {
case _: JsUndefined =>
json \ "l" match {
case _: JsUndefined => JsSuccess(A(_, _))
case lJS => lJS.validate[Long] map (l => C.apply(_, _, l))
}
case kJS => kJS.validate[Long] map (k => B.apply(_, _, k))
}
}
}
}
import play.api.libs.functional.{Applicative => PlayApplicative}
object PlayIntegration {
/** All Play Applicatives "should" map to scalaz Applicatives */
implicit def applicativeAsScalazApplicative[F[_] : PlayApplicative] = new scalaz.Applicative[F] {
def point[A](a: => A): F[A] = implicitly[PlayApplicative[F]].pure(a)
def ap[A, B](fa: => F[A])(f: => F[(A) => B]): F[B] = implicitly[PlayApplicative[F]].apply(f, fa)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment