在 Scala 中编写验证函数 [英] Composing validating functions in Scala

查看:39
本文介绍了在 Scala 中编写验证函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我需要编写一个验证函数 Validate[A]:

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

如果输入有效,该函数返回带有输入的 Success 或带有错误列表的 Failure 如果输入无效.

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.

例如

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)我可以compose 验证函数如下:

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

假设现在我需要验证 X:

Suppose now that I need to validate X:

case class X(x1: Int, // should be positive 
             x2: Int) // should be even

因为 Validation 是一个应用函子 Validate 也是一个应用函子.

Since Validation is an applicative functor Validate is an applicative functor too.

val x: Validate[X] = (isPositive |@| isEven)(X.apply) 

有意义吗?

推荐答案

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

You can compose validations when the left hand type is a semigroup. Your List works, but scalaz provides a built in type ValidationNel[L, R] = Validation[NonEmptyList[L], R] which you should use instead. There's several convenience functions like aValidation.toValidationNel for lifting values with single errors. The composed Validation will have a left hand side with all failures accumulated or a right hand with the success applied to your function

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 的简写) 形式的新单个函数的组合

If you're looking for composition to a new single function in the shape of (V as shorthand for Validation)

(A => V[L, B], A => V[L, C]) => (A => V[L, (B, C)])

那么我不太确定正确的方法.感觉应该有一两个组合器可以做到这一点,但我还没有找到.

Then I'm not quite sure of the right way. It feels like there should be a combinator or two that would do just this but I haven't found it.

我已经设法写了这篇作文,但我觉得可能有更好的方法.

I have managed to write this composition, but I feel like there might be a better way.

  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 中编写验证函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆