用Scala编写验证函数
假设我需要编写一个验证函数用Scala编写验证函数,scala,validation,scalaz,Scala,Validation,Scalaz,假设我需要编写一个验证函数Validate[a]: type Status[A] = Validation[List[String], A] type Validate[A] = A => Status[A] // should be Kleisli 如果输入有效,则函数返回带有输入的成功;如果输入无效,则返回带有错误列表的失败 比如说, val isPositive: Validate[Int] = {x: Int => if (x > 0) x.success els
Validate[a]
:
type Status[A] = Validation[List[String], A]
type Validate[A] = A => Status[A] // should be Kleisli
如果输入有效,则函数返回带有输入的成功
;如果输入无效,则返回带有错误列表的失败
比如说,
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提供了一个内置的
类型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
作为验证的缩写)形式的新单个函数的组合
那么我不太确定正确的方法。感觉应该有一个或两个组合器可以做到这一点,但我还没有找到它
我已经设法写了这篇作文,但我觉得可能有更好的方法
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 }
}
}
是的,我想知道如何组合返回验证的函数。我认为,由于这些函数是Kleisli
,我们可以将它们完全组合为Validation
值。这就是我问这个问题的原因。@Michael,我刚刚写了一个。我相信还有更好的方法,因为我的Validate
是Kleisli
(我已经更新了问题),所以我可以免费得到这样一篇作文。@Michael我同意,我想你可以,但我想不出来好吧,现在我觉得我应该去REPL,试着将解决方案编码为real,而不是询问:)验证只形成一个半群,其中左半群和右半群都需要提醒。我认为Validation[E,A]
要求E
是一个半群,但它可能不是。它要求E:semigroup
形成一个应用程序,它要求E:semigroup,A:semigroup
形成一个半群。看不到重复,但有点相关,可能导致不同的方法:
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 }
}
}