5

我是函数式编程工作的初学者,我有一个 ValidationNEL[A,B] 序列,我想将错误累积到一个新的 ValidationNEL[A,B] 中。这取决于 B 是来自遗留代码的可变数据结构这一事实,因此保存 Seq[B] 会过于冗长。

我从其他帖子中知道,通过序列方法可以累积错误和成功:处理 Scalaz6 验证列表

根据我的理解,这一切都是为了编写一个合适的 Applicative 并且可能是一个合适的 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)
  }

我该如何开始?当我试图查看 Scalaz 源代码以了解如何实现我的 Applicative 时,我感到非常困惑。我什至无法找出哪个应用程序允许在验证中累积失败和成功。

4

2 回答 2

3

迟到了,但从 Scalaz 7.0.4 开始,我们可以这样做:

  def takeLastSuccess[A, B](seq: Seq[ValidationNel[A, B]]) = {
      implicit val useLast = Semigroup.lastSemigroup[B]
      seq reduceLeft (_ +++ _)
  }
于 2013-11-12T11:10:39.157 回答
2

现在我更好地理解了你的问题,这很简单:

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

当您对这个 Scala 进行排序时,类型会出现一些问题,因此您需要使用类型 lambda。序列是从 Seq[Something[X]] 到 Something[Seq[X]] 的一个很好的捷径。最后,我们只是映射成功并从 B 的序列中获取最后一个 B。

从您引用的帖子中删除示例,这是我从 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"))
于 2013-02-20T02:52:35.670 回答