Scalaz Validation with applicative functor | @ | does not work

I am trying to use Scalaz 7 validation in my application. However, I had a problem with the applicative functor |@| combined my failures. Here is 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 simply return ValidationResults .

The problem is that this code will not compile. Error message:

 Type mismatch, expected F0.type#M[NotInferedB], actual: ValidationResult 

I don't know what this means ... do I need to provide Scala with additional type information?

What I'm trying to accomplish is if all fields are successNel s, then return this, otherwise return a combination of all failureNel s.

Changed |@| from the previous version of Scalaz? Because even if I do something like:

 ().successNel |@| ().successNel 

I get the same error.

Update

I started digging around the source of Scalaz, and I found +++ that seems to do what I want.

What is the difference between +++ and |@| ?

+6
source share
1 answer

Scalaz adaptive linker syntax ( |@| ) gives you a way to β€œlift” functions into an applicative functor. Suppose we have the following results, for example:

 val xs: ValidationNel[String, List[Int]] = "Error!".failNel val ys: ValidationNel[String, List[Int]] = List(1, 2, 3).success val zs: ValidationNel[String, List[Int]] = List(4, 5).success 

We can raise the list concatenation function ( ++ ) in Validation as follows:

 scala> println((ys |@| zs)(_ ++ _)) Success(List(1, 2, 3, 4, 5)) scala> println((xs |@| ys)(_ ++ _)) Failure(NonEmptyList(Error!)) scala> println((xs |@| xs)(_ ++ _)) Failure(NonEmptyList(Error!, Error!)) 

This syntax is a little strange - it is very different from how you, for example, raise functions into an applicative functor in Haskell, and is designed in such a way as to outwit a system of insanity like w60. See my answer here or blog post here for further discussion.

One part of the oddity is that xs |@| ys xs |@| ys doesn't really mean anything - it's essentially a list of arguments to be applied to a function that it will raise to its application functor and apply to itself.

+++ on Validation is a much simpler creature view - it's just the operation of adding a Semigroup instance to a type (note that you can equivalently use the semigroup operator Scalaz |+| here instead of +++ ). You give it two Validation results with the corresponding semigroup types, and it gives you another Validation not some terrible ApplyOps thing.


As an additional note, in this case the addition operation for the Validation semigroup coincides with the operation of the right-hand semigroup raised in Validation :

 scala> (xs |+| ys) == (xs |@| ys)(_ |+| _) res3: Boolean = true 

This will not always be the case, however (this is not for \/ , for example, when a semigroup accumulates errors, but the applicative functor does not).

+10
source

Source: https://habr.com/ru/post/949692/


All Articles