【问题标题】:Composing validating functions in Scala在 Scala 中编写验证函数
【发布时间】:2015-05-29 10:54:53
【问题描述】:

假设我需要编写一个验证函数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) 

有意义吗?

【问题讨论】:

  • 验证只形成一个半群,其中左右都形成半群
  • 感谢提醒。我认为Validation[E, A] 要求 E 是一个半群,但它可能不是。
  • 它需要E: Semigroup 来形成一个应用程序,它需要E: Semigroup, A: Semigroup 来形成一个半群。见ValidationInstances
  • 不是重复的,但有些相关,可能会导致不同的方法:meta.plasm.us/posts/2013/06/05/applicative-validation-syntax

标签: scala validation scalaz


【解决方案1】:

当左侧类型是半群时,您可以编写验证。您的 List 有效,但 scalaz 提供了一个内置的 type ValidationNel[L, R] = Validation[NonEmptyList[L], R] ,您应该使用它。有几个方便的功能,如aValidation.toValidationNel,用于提升具有单个错误的值。组合的 Validation 将有一个累积所有失败的左侧或一个将成功应用于您的函数的右侧

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 }
  }
}

【讨论】:

  • 是的,我想知道如何编写返回Validation函数。我认为由于这些函数是Kleisli,我们可以将它们完全组合为Validation 值。这就是我问这个问题的原因。
  • @Michael 我刚刚写了一个。我敢肯定有更好的方法
  • 我仍然认为,因为我的ValidateKleisli(我已经更新了问题)我得到了这样的作文免费
  • @Michael 我同意,我认为你可以,但我想不通
  • 好的,现在我觉得我应该去 REPL 并尝试编写解决方案 for real 而不是 SO :)
猜你喜欢
  • 1970-01-01
  • 2012-06-26
  • 1970-01-01
  • 1970-01-01
  • 2010-10-11
  • 2015-11-02
  • 1970-01-01
  • 2011-09-06
  • 1970-01-01
相关资源
最近更新 更多