2011-04-21 32 views
10

Estamos usando el rasgo de validación scalaz en nuestro proyecto para validar los parámetros de HTTP. El caso común está tomando unos valores validados y la realización de neccessary acción sólo si todos ellos son válidos, lista de errores de regresar de otro modo:Validación de Scalaz y límites de ApplicativeBuilder

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

Esto funciona muy bien, hasta que tenemos que utilizar más de 8 parámetros, porque | @ | el operador construye ApplicativeBuilder, que está limitado a 8 argumentos. ¿Hay alguna otra manera de realizar dicha validación todo en uno, preferiblemente manteniendo el código legible?

+2

Hemos actualizar el límite (arbitraria) de 'ApplicativeBuilder' a 12 en la próxima versión. – retronym

Respuesta

11

desea utilizar el método <*>, junto con una única llamada al map (o si lo prefiere). Puede seguir usando <*> indefinidamente.

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

No olvide que 'getSomeResponse' debe ser una función curried, es decir' Int => Int => Int => Int'. – retronym

+2

¿No tenemos allí el orden inverso de los argumentos? Me refiero a obtener el mismo resultado que en la pregunta que necesitamos para escribir 'param3Val <*> (param2Val <*> (param1Val map getSomeResponse))'. – CheatEx

+0

@CheatEx tiene razón acerca de la orden inversa – ron

2

un par de maneras de hacerlo:

  1. Lift la función relevante para Validation contexto, y luego aplicarlo a los valores.

    getSomeResponse.lift[({ type L[X] = Validation[Y, X] })#L] apply (
        param1Val, param2Val, param3Val 
    ) 
    
  2. Utilice la comprensión de mónada.

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

Por supuesto, la versión monádica no acumulará errores simplemente rescatar en la primera. – ron

+0

ron, a la derecha. Debería haber mencionado eso. – missingfaktor

+0

Mientras estuvo aquí, el levantamiento usaría la instancia de Functor, por lo que también se desconectará. – ron