Suppose I need to write a validating function Validate[A]:
type Status[A] = Validation[List[String], A]
type Validate[A] = A => Status[A] // should be Kleisli
The function returns either a Success with the input if the input is valid or a Failure with the list of errors if it is not.
For example,
val isPositive: Validate[Int] = {x: Int =>
if (x > 0) x.success else List(s"$x is not positive").failure
}
val isEven: Validate[Int] = {x: Int =>
if (x % 2 == 0) x.success else List(s"$x is not even").failure
}
Since Validation is a semigroup Validate is semigroup too and (if I define it as Kleisli) I can compose validating functions as follows:
val isEvenPositive = isEven |+| isPositive
Suppose now that I need to validate X:
case class X(x1: Int, // should be positive
x2: Int) // should be even
Since Validation is an applicative functor Validate is an applicative functor too.
val x: Validate[X] = (isPositive |@| isEven)(X.apply)
Does it make sense ?
Validation[E, A]requiresEto be a semigroup but it probably does not.E: Semigroupto form an applicative and it requiresE: Semigroup, A: Semigroupto form a semigroup. See ValidationInstances