5

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

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

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

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

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

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

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

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

4

4 回答 4

5

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

于 2012-08-10T14:54:56.237 回答
4

我会做这样的事情:

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))
于 2012-08-10T16:36:55.510 回答
1

您需要的是大约将Either[E, A]a 转换为Writer[List[E], A]. Writermonad 记录您遇到的错误。

于 2012-08-29T14:00:09.160 回答
0

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

不知道 Scalaz 是否对此有任何幻想。

于 2012-08-10T15:00:46.437 回答