Last active
November 17, 2015 11:09
-
-
Save stanch/9042312 to your computer and use it in GitHub Desktop.
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
import scala.language.higherKinds | |
import play.api.libs.functional._ | |
import shapeless._ | |
import shapeless.ops.hlist.RightFolder | |
import play.api.data.mapping.{ From, Reader, Rule } | |
import play.api.libs.json.{Json, JsValue} | |
import play.api.data.mapping.json.Rules._ | |
object applicativeFolder2 extends Poly2 { | |
// Rule[I, X] :: Rule[I, L] -> Rule[I, X :: L] | |
implicit def caseApp[A, B <: HList, I, F[_, _]](implicit app: Applicative[({ type λ[O] = F[I, O] })#λ]) = | |
at[F[I, A], F[I, B]] { (a, b) ⇒ | |
app.apply[A, A :: B](app.map[B, A ⇒ A :: B](b, x ⇒ y ⇒ y :: x), a) | |
} | |
// X :: Rule[I, L] -> Rule[I, X :: L] | |
// uses ruleApplicative[I].pure | |
implicit def casePure[A, B <: HList, I, F[_, _]](implicit app: Applicative[({ type λ[O] = F[I, O] })#λ], pure: A <:!< F[_, _]) = | |
at[A, F[I, B]] { (a, b) ⇒ | |
app.apply[A, A :: B](app.map[B, A ⇒ A :: B](b, x ⇒ y ⇒ y :: x), app.pure(a)) | |
} | |
} | |
// Rule[I, X] :: Rule[I, Y] :: ... :: HNil -> Rule[I, X :: Y :: ... :: HNil] | |
def liftRule[I] = new RuleLifter[I] | |
class RuleLifter[I] { | |
val app = Rule.applicativeRule[I] | |
def apply[L <: HList](l: L)(implicit folder: RightFolder[L, Rule[I, HNil], applicativeFolder2.type]) = | |
l.foldRight(app.pure(HNil: HNil))(applicativeFolder2) | |
} | |
// (Reader[I] ⇒ Rule[I, X] :: Rule[I, Y] :: ... :: HNil) -> Rule[I, X :: Y :: ... :: HNil] | |
def from[I] = new FromMaker[I] | |
class FromMaker[I] { | |
def apply[L <: HList, O](l: Reader[I] ⇒ L)(implicit folder: RightFolder.Aux[L, Rule[I, HNil], applicativeFolder2.type, Rule[I, O]]) = | |
From[I](__ ⇒ liftRule[I](l(__))) | |
} | |
// a wild case class appears | |
case class A(foo: Int, bar: Int, baz: Int) | |
val r = from[JsValue] { __ ⇒ | |
(__ \ "foo").read[Int] :: | |
(__ \ "bar").read[Int] :: | |
3 :: // turns into Rule(_ ⇒ Success(3)) | |
HNil | |
}.fmap(Generic[A].from) // hurray, Rule[JsValue, A]! |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment