简体   繁体   中英

Scalaz validation and ApplicativeBuilder limits

We're using scalaz validation trait in our project to validate HTTP parameters. The common case is taking few validated 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:

  1. 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 ) 
  2. Use monad comprehension.

     for { x1 <- param1Val x2 <- param2Val x3 <- param3Val } yield getSomeResponse(x1, x2, x3) 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM