2012-06-23 41 views
9

Soy bastante nuevo en scalaz y comencé con las validaciones.Aplanar las validaciones de Scalaz anidadas

Tengo algunas funciones de validación de la forma:

def validateXyz(...): ValidationNEL[String, String] = ... 

entonces yo estoy usando el estilo aplicativo para combinar múltiples validaciones y luego llamar a otra función que también devuelve una validación:

(validateXyz(...) |@| validateAbc(...)) { (first, second) => 
    otherFunction(first, second) 
} 

donde,

def otherFunction(first: String, second: String): ValidationNEL[String, String] = ... 

Sin embargo, al llamar al tipo anterior, el tipo resultante es decir:

val result: ValidationNEL[String, ValidationNEL[String, String]] = ... 

puedo desempaquetar esto llamando a veces en el resultado con dos funciones, la primera que acaba propaga la NEL como una falla y el segundo que acaba propaga su argumento:

def propagateF(result: NonEmptyList[String]): ValidationNEL[String, String] = result.fail 
def propagateV(result: ValidationNEL[String, String]) = result 

result.fold(propagateF, propagateV) 
// result type: ValidationNEL[String, String] 

Este funciona y devuelve los tipos y resultados correctos. Sin embargo, no parece la solución correcta, así que me falta algo. ¿Qué debo hacer para evitar este horrible pliegue al final?

Respuesta

8

Lo que está buscando aquí es monadic join.

El hecho es que Validation en sí mismo no es realmente una mónada, ya que el lado del error tiene una estructura Semigroup que no puede ser preservada por Monad. Pero siempre puede desplegar en la mónada Either si es necesario. Esta funcionalidad es proporcionada por flatMap.

(validateXyz(...) |@| validateAbc(...))(otherFunction).flatMap(x => x) 

Si tiene un error en el exterior, el resultado será ese error. Si tiene un error dentro de un éxito, el resultado será el error interno. De lo contrario, el resultado será un éxito. Tenga en cuenta la imposibilidad de tener un error tanto en el interior como en el exterior. Es por eso que debe usar Applicative en lugar de Monad si desea combinar errores.