I'm trying to use Scalaz 7 Validation in my app. However, I'm having an issue getting the |@| applicative functor to coalesce my failures. Here's the code I have:
type ValidationResult = ValidationNel[String, Unit]
def validate[A: ClassTag](instance: A, fieldNames: Option[Seq[String]] = None): ValidationResult = {
val fields = classTag[A].runtimeClass.getDeclaredFields
val fieldSubset = fieldNames match {
case Some(names) => fields.filter { field => names.contains(field.getName) }
case None => fields
}
fieldSubset.map {
field => field.getAnnotations.toSeq.map {
field.setAccessible(true)
val (name, value) = (field.getName, field.get(instance))
field.setAccessible(false)
annotation => annotation match {
case min: Min => minValidate(name, value, min.value())
case size: Size => sizeValidate(name, value, size.min(), size.max())
}
}
}.flatten[ValidationResult].foldLeft(().successNel[String])(_ |@| _)
}
The minValidate and sizeValidate functions just return ValidationResults.
The problem is, this code won't compile. The error message is:
Type mismatch, expected F0.type#M[NotInferedB], actual: ValidationResult
I have no idea what that means... do I need to give Scala more type info?
What I'm trying to accomplish is, if all fields are successNels, then return that, otherwise, return a combination of all the failureNels.
Has |@| changed since previous version of Scalaz? Because even if I do something like:
().successNel |@| ().successNel
I get the same error.
Update
I started poking around the Scalaz source and I found the +++ which seems to do what I want.
What's the difference between +++ and |@|?
Scalaz's applicative builder syntax (
|@|) gives you a way of "lifting" functions into an applicative functor. Suppose we have the following results, for example:We can lift the list concatenation function (
++) into theValidationlike this:This syntax is a little weird—it's very unlike how you lift functions into an applicative functor in Haskell, for example, and is designed this way primarily to outsmart Scala's fairly stupid type inference system. See my answer here or blog post here for more discussion.
One part of the weirdness is that
xs |@| ysdoesn't really mean anything on its own—it's essentially an argument list that's waiting to be applied to a function that it will lift into its applicative functor and apply to itself.The
+++onValidationis a much simpler kind of creature—it's just the addition operation for theSemigroupinstance for the type (note that you could equivalently use Scalaz's semigroup operator|+|here in place of+++). You give it twoValidationresults with matching semigroup types and it gives you anotherValidation—not some awfulApplyOpsthing.As a side note, in this case the addition operation for
Validation's semigroup is the same as the semigroup operation for the right side lifted into theValidation:This won't always be the case, however (it's not for
\/, for example, where the semigroup accumulates errors but the applicative functor doesn't).