简体   繁体   English

仅累积Scalaz中的验证错误

[英]Accumulating only validation errors in Scalaz

I am a beginner in the work of functional programming and I have a sequence of ValidationNEL[A,B] and I would like to accumulate the errors into a new ValidationNEL[A,B]. 我是函数式编程的初学者,我有一个ValidationNEL [A,B]序列,我想将错误累积到一个新的ValidationNEL [A,B]中。 This depends on the fact that B is a mutable data structure coming from legacy code, and so it would be oververbose to hold a Seq[B]. 这取决于以下事实:B是来自遗留代码的可变数据结构,因此持有Seq [B]将是多余的。

I know from other posts that cumulating errors and success is possible through the sequence method: Processing a list of Scalaz6 Validation 我从其他帖子中知道,通过sequence方法可以累积错误和成功: 处理Scalaz6验证列表

From my understanding it all comes to writing a proper Applicative and maybe a proper Traverse. 根据我的理解,所有这一切都涉及编写适当的应用程序,甚至可能是适当的导线。

  trait MA[M[_], A] extends PimpedType[M[A]] with MASugar[M, A] {

    def sequence[N[_], B](implicit a: A <:< N[B], t: Traverse[M], n: Applicative[N]): N[M[B]] =
    traverse((z: A) => (z: N[B]))

  def traverse[F[_],B](f: A => F[B])(implicit a: Applicative[F], t: Traverse[M]): F[M[B]] =
    t.traverse(f, value)
  }

How do I start? 我该如何开始? When I tried to look into Scalaz source code to find out how to implement my Applicative, I got extremely confused. 当我尝试研究Scalaz源代码以了解如何实现我的Applicative时,我感到非常困惑。 I was not even able to find out which applicative allows accumulating both failures and success in Validation. 我什至无法找出哪个应用程序可以同时累积验证中的失败和成功。

Late to the party, but as of Scalaz 7.0.4, we can do this: 聚会晚了,但是从Scalaz 7.0.4开始,我们可以这样做:

  def takeLastSuccess[A, B](seq: Seq[ValidationNel[A, B]]) = {
      implicit val useLast = Semigroup.lastSemigroup[B]
      seq reduceLeft (_ +++ _)
  }

Now that I understand your question a little better, this is pretty straight forward: 现在,我对您的问题有了更好的了解,这很简单:

def takeLastSuccess[A, B](seq:Seq[ValidationNEL[A, B]]) = 
    seq.sequence[({type l[a] = ValidationNEL[A, a]})#l, B].map(_.last)

When you sequence this Scala has some trouble with the types so you need to use a type lambda. 当您对这个Scala进行排序时,在类型方面会遇到一些麻烦,因此您需要使用lambda类型。 Sequence is a nice shortcut to go from Seq[Something[X]] to Something[Seq[X]]. 从Seq [Something [X]]到Something [Seq [X]],序列是一个不错的捷径。 Finally, we just map the success and get the last B from the sequence of B's. 最后,我们只是映射成功并从B的序列中获取最后一个B。

Going off the example from the post you cited , here's what I get from the REPL: 您引用的帖子中获得示例,这是我从REPL中获得的信息:

scala>   import scalaz._, Scalaz._
import scalaz._
import Scalaz._

scala>   type ExceptionsOr[A] = ValidationNEL[Exception, A]
defined type alias ExceptionsOr

scala>   val successResults: Seq[ExceptionsOr[Int]] = Seq(
     |     "13".parseInt.liftFailNel, "42".parseInt.liftFailNel
     |   )
successResults: Seq[ExceptionsOr[Int]] = List(Success(13), Success(42))

scala>   val failResults: Seq[ExceptionsOr[Int]] = Seq(
     |     "13".parseInt.liftFailNel, "a".parseInt.liftFailNel, "b".parseInt.liftFailNel
     |   )
failResults: Seq[ExceptionsOr[Int]] = List(Success(13), Failure(NonEmptyList(java.lang.NumberFormatException: For input string: "a")), Failure(NonEmptyList(java.lang.NumberFormatException: For input string: "b")))

scala>   def takeLastSuccess[A, B](seq:Seq[ValidationNEL[A, B]]) = seq.sequence[({type l[a] = ValidationNEL[A, a]})#l, B].map(_.last)
takeLastSuccess: [A, B](seq: Seq[scalaz.Scalaz.ValidationNEL[A,B]])scalaz.Validation[scalaz.NonEmptyList[A],B]

scala>   takeLastSuccess(successResults)
res0: scalaz.Validation[scalaz.NonEmptyList[Exception],Int] = Success(42)

scala>   takeLastSuccess(failResults)
res1: scalaz.Validation[scalaz.NonEmptyList[Exception],Int] = Failure(NonEmptyList(java.lang.NumberFormatException: For input string: "a", java.lang.NumberFormatException: For input string: "b"))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM