假设我需要编写一个验证函数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)
有意义吗?
答案 0 :(得分:1)
当左手类型是半群时,您可以编写验证。您的列表有效,但scalaz提供了内置的select switchID, patchCordID from switch
where patchCordID in (select distinct patchCordID from switch where switchID=197)
,您应该使用它。有一些便利函数,如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 }
}
}