假设我需要编写一个验证函数 Validate[A]
:
type Status[A] = Validation[List[String], A]
type Validate[A] = A => Status[A] // should be Kleisli
该函数返回
Success
如果输入有效,则使用输入或 Failure
如果不是,则带有错误列表。例如,
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
}
自
Validation
是半群Validate
也是半群并且(如果我将其定义为 Kleisli
)我可以按如下方式组合验证函数:val isEvenPositive = isEven |+| isPositive
现在假设我需要验证
X
:case class X(x1: Int, // should be positive
x2: Int) // should be even
自
Validation
是一个应用仿函数 Validate
也是一个应用仿函数。val x: Validate[X] = (isPositive |@| isEven)(X.apply)
是否有意义 ?
最佳答案
当左手类型是半群时,您可以编写验证。您的列表有效,但 scalaz 提供了一个内置的 type ValidationNel[L, R] = Validation[NonEmptyList[L], R]
你应该使用它。有几个方便的功能,如 aValidation.toValidationNel
用于提升具有单个错误的值。组合验证的左侧将累积所有失败,或右侧将成功应用于您的功能
def foo: ValidationNel[String, Int]
def bar: ValidationNel[String, Double]
val composed: ValidationNel[String, Double] = foo(input) |@| bar(input) apply { (i: Int, d: Double) => i * d }
如果您正在寻找以 (
V
作为 Validation
的简写形式) 形式的新单个函数的组合(A => V[L, B], A => V[L, C]) => (A => V[L, (B, C)])
然后我不太确定正确的方法。感觉应该有一两个组合器可以做到这一点,但我还没有找到。
我已经设法写了这篇作文,但我觉得可能有更好的方法。
def composeV[A, B, C, L: Semigroup](f: A => Validation[L, B], g: A => Validation[L, C]): A => Validation[L, (B, C)] = {
import scalaz.syntax.arrow._
import scalaz.syntax.apply._
import scalaz.std.function.function1Instance
val oneInput: (A) => (Validation[L, B], Validation[L, C]) = f &&& g
oneInput andThen {
case (vb, vc) =>
vb |@| vc apply { case x: (B, C) => x }
}
}
这是另一种方式:
def composeV[A, B, C, L: Semigroup](f: A => Validation[L, B], g: A => Validation[L, C]): A => Validation[L, (B, C)] = {
import scalaz.syntax.apply._
import scalaz.std.function.function1Instance
f |@| g apply { case (vb, vc) =>
vb |@| vc apply { case x: (B, C) => x }
}
}
关于scala - 在 Scala 中编写验证函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30527740/