Ограничения проверки Scalaz и ApplicativeBuilder

Мы используем свойство валидации scalaz в нашем проекте для проверки параметров HTTP. Обычный случай принимает несколько подтвержденных значений и выполняет необходимые действия только в том случае, если все они действительны, возвращая список ошибок в противном случае:

(pavam1Val.liftFailNel |@|
 param2Val.liftFailNel |@|
 param3Val.liftFailNel) {
    getSomeResponse(_, _, _)
}

Это работает хорошо, пока мы не будем использовать более 8 параметров, потому что | @| оператор-конструктор ApplicativeBuilder, который ограничен 8 аргументами. Есть ли другой способ выполнить такую ​​проверку "все в один раз", предпочтительно, чтобы код читался?

Ответ 1

вы хотите использовать метод <*>, а также один вызов map (или , если хотите). Вы можете продолжать использовать <*> неопределенно.

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)

Ответ 2

Еще несколько способов сделать это:

  • Поднимите соответствующую функцию в контекст Validation, а затем примените ее к значениям.

    getSomeResponse.lift[({ type L[X] = Validation[Y, X] })#L] apply (
      param1Val, param2Val, param3Val
    )
    
  • Используйте понимание монады.

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