bjfypw
Last Updated: February 25, 2016
·
1.526K
· teamon
9fae8c5d475fe322a3a74e53d56ee2a0

Compose play.api.concurrent.Promise and scalaz.Validation using Kleisli arrow

If you use scalaz.Validation (and you should) inside Play 2.0 application you might end up with few sequential asynchronous operations and then use for comprehension or nested flatMap to get the result.

Here is much better approach (based on Scalaz 6)

import play.api.Play.current
import play.api.libs.concurrent.{Promise,Akka}
import scalaz._
import Scalaz._

type VA[T] = Promise[ValidationNEL[String, T]]

implicit def VABind = new Bind[VA] {
  def bind[A,B](a: VA[A], f: A => VA[B]) = a.flatMap { res =>
    res.fold(e => Promise.pure(e.fail), s => f(s))
  }
}

val p1: Int => VA[Int] = a => Akka.future { if(a > 0) a.success else "negative".fail.liftFailNel }
val p2: Int => VA[Int] = a => Akka.future { if(a % 2 === 0) a.success else "not 2x".fail.liftFailNel }
val p3: Int => VA[Int] = a => Akka.future { if(a % 3 === 0) a.success else "not 3x".fail.liftFailNel }

val p4: Int => VA[Int] = kleisli(p1) >=> p2 >=> p3

// uncomment to try inside play console
// new play.core.StaticApplication(new java.io.File(".")) 

p4(-1).value.get  // Failure(NonEmptyList(negative))
p4(1).value.get   // Failure(NonEmptyList(not 2x))
p4(2).value.get   // Failure(NonEmptyList(not 3x))
p4(6).value.get   // Failure(NonEmptyList(not 2x))
Say Thanks
Respond