Se você usar scalaz.Validation (e deveria) dentro do aplicativo Play 2.0, você pode acabar com poucas operações sequenciais assíncronas e usar para compreensão ou flatMap aninhado para obter o resultado.
Aqui está uma abordagem muito melhor (com base no 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))