【问题标题】:Does Scalaz have something to accumulate in both error and success?Scalaz 在错误和成功中都有积累吗?
【发布时间】:2012-08-10 14:39:39
【问题描述】:

我开始使用 Scalaz 7 验证和/或析取来处理可能失败的操作列表并管理其结果。

这种用例有两个有据可查的案例:

1/ 您想检查某事的条件列表,并累积每个错误(如果有)。在这里,您总是走到列表的末尾,如果出现任何错误,您将作为全局结果失败。 这是一个应用函子在起作用。

2/ 你想执行几个可能失败的步骤,并在第一个失败时停止。 在这里,我们有一个在 Scala 中很好理解的 monad。

所以,我还有两个相同的用例,但在任何先例中似乎都不太合适: 我想处理一个可能失败的步骤列表,并累积错误和成功结果(例如:它是对文件的修改列表,可能会发生错误,因为那是外部世界,成功是我想保留以备后用的补丁)。

这两个用例的区别仅在于我想提前停止(在第一个错误时)或转到列表的末尾。

好的,那么正确的做法是什么?

(写这个问题让我认为这只是一个简单的 foldLeft,是吗?我会让这个问题在这里验证,如果其他人想知道)

【问题讨论】:

    标签: scala monads fold scalaz applicative


    【解决方案1】:

    查看Validation#append 或其别名Validation#+|+。给定两个验证,如果两者都成功,则返回附加值的成功。如果两者都失败,则返回附加值的失败。否则,它返回成功的值。这需要成功类型的隐式 Semigroup 实例。

    【讨论】:

      【解决方案2】:

      我会这样做:

      scala> List(1.success[String], 2.success[String], "3".failure[Int], "4".failure[Int]).partition(_.isSuccess)
      res2: (List[scalaz.Validation[java.lang.String,Int]], List[scalaz.Validation[java.lang.String,Int]]) = (List(Success(1), Success(2)),List(Failure(3), Failure(4)))
      
      scala> val fun = (_:List[Validation[String, Int]]).reduceLeft(_ append _)
      fun: List[scalaz.Validation[String,Int]] => scalaz.Validation[String,Int] = <function1>
      
      scala> fun <-: res2 :-> fun
      res3: (scalaz.Validation[String,Int], scalaz.Validation[String,Int]) = (Success(3),Failure(34))
      

      UPD:#129#130 合并后,您可以将fun 更改为(_:List[Validation[String, Int]]).concatenate(_:List[Validation[String, Int]]).suml

      bimap 像这样:

      scala> List(1.success[String], 2.success[String], "3".failure[Int], "4".failure[Int]).partition(_.isSuccess).bimap(_.suml, _.suml)
      res6: (scalaz.Validation[java.lang.String,Int], scalaz.Validation[java.lang.String,Int]) = (Success(3),Failure(34))
      

      【讨论】:

      • 请注意,这使用默认的 monoid 进行验证,它委托给 +++ 进行追加。 +++ 返回第一个失败,而不是附加的失败。例如:scala> List(1.failure[String], 2.failure[String]).reduceLeft { _ |+| _ } res0: scalaz.Validation[Int,String] = Failure(1)
      • @mpilquist 好吧,这种行为最近发生了变化:github.com/scalaz/scalaz/pull/114。更新了我的答案以更准确地说明这一点。
      • 嗯,看看 Tony 的析取合并。拉动 114 的变化似乎丢失了。我上面运行的代码来自本地最新版本的 scalaz-7。
      • 现在这很令人困惑。我很确定,因为我实际上是在改变那个实例。更新了我的答案。
      • 是的,我敢打赌这是偶然的。我会跟托尼提一下,看看他的想法。
      【解决方案3】:

      您需要将Either[E, A] 大致转换为Writer[List[E], A]Writer monad 记录您遇到的错误。

      【讨论】:

        【解决方案4】:

        听起来你想要一对(SomveValue, List[T]),其中T 是你的“失败”,尽管我称之为“警告”或“日志”,因为你仍然会得到结果,所以它并不是真正的失败。

        不知道 Scalaz 是否对此有什么特别的想法。

        【讨论】:

        • (W, A) 是 Writer[A] monad,W 通常是一个半群(可以累加)。
        猜你喜欢
        • 1970-01-01
        • 2020-04-04
        • 1970-01-01
        • 2021-05-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-02-11
        • 1970-01-01
        相关资源
        最近更新 更多