Scalaz validation and ApplicativeBuilder limits
We're using scalaz validation trait in our project to validate HTTP parameters. The common case is taking few validate开发者_开发问答d values and performing neccessary action only if all of them are valid, returning list of errors otherwise:
(pavam1Val.liftFailNel |@|
param2Val.liftFailNel |@|
param3Val.liftFailNel) {
getSomeResponse(_, _, _)
}
This works nice, until we have to use more than 8 parameters, because |@| operator constructs ApplicativeBuilder, which is limited to 8 arguments. Is there another way to perform such all-at-once validation, preferably keeping the code readable?
you want to use the <*>
method, along with a single call to map
(or ∘
if you prefer). You can keep using <*>
indefinitely.
scala> val param1Val = success[String, Int](7)
param1Val: scalaz.Validation[String,Int] = Success(7)
scala> val param2Val = failure[String, Int]("abc")
param2Val: scalaz.Validation[String,Int] = Failure(abc)
scala> val param3Val = success[String, Int](9)
param3Val: scalaz.Validation[String,Int] = Success(9)
scala> val r = param1Val <*> (param2Val <*> (param3Val map getSomeResponse))
r: scalaz.Validation[String,Int] = Failure(abc)
A couple more ways to do it:
Lift the relevant function to
Validation
context, and then apply it to the values.getSomeResponse.lift[({ type L[X] = Validation[Y, X] })#L] apply ( param1Val, param2Val, param3Val )
Use monad comprehension.
for { x1 <- param1Val x2 <- param2Val x3 <- param3Val } yield getSomeResponse(x1, x2, x3)
精彩评论