scala - 如何对 Set[ValidatedNel[String, Double]] 求和?

标签 scala functional-programming scala-cats

我有这个:

Set[ValidatedNel[String, Double]] 

我想将其中的 double 相加得到:

ValidatedNel[String, Double]

如果值中的某些元素是,那么我希望有匹配的字符串。

我玩过 Set.sum 和 Numeric 都无济于事......

下面是我想要实现的测试:

  test("Summing ValidatedNel works") {
    val val1: ValidatedNel[String, Double] = Valid(1.0)
    val val2: ValidatedNel[String, Double] = Valid(2.0)
    val values: Set[ValidatedNel[String, Double]] = Set(val1, val2)

    val validatedNelNumeric: Numeric[ValidatedNel[String, Double]] = ???
    val sum = values.sum(validatedNelNumeric)

    assert(sum == Valid(3.0))
  }

我没有设法创建经过验证的 NelNumeric...

最佳答案

首先:在这种情况下使用集合感觉有点奇怪(对于 Validated[..., Double] 值的集合)。您关心 Set 语义的哪一部分?无序性?唯一性?

通常,总结具有 Monoid 实例的元素的最直接方法是对具有 Foldable 的元素使用 combineAll 方法实例——例如 List(但不是 Set)。

import cats.data.{ Validated, ValidatedNel }
import cats.instances.double._, cats.instances.list._
import cats.syntax.foldable._
// or just import cats.implicits._

val val1: ValidatedNel[String, Double] = Validated.valid(1.0)
val val2: ValidatedNel[String, Double] = Validated.valid(2.0)
val bad1: ValidatedNel[String, Double] = Validated.invalidNel("foo")
val bad2: ValidatedNel[String, Double] = Validated.invalidNel("bar")

val values = Set(val1, val2)
val withSomeBadOnes = Set(val1, bad1, val2, bad2)

然后:

scala> values.toList.combineAll
res0: cats.data.ValidatedNel[String,Double] = Valid(3.0)

scala> withSomeBadOnes.toList.combineAll
res1: cats.data.ValidatedNel[String,Double] = Invalid(NonEmptyList(foo, bar))

我猜这就是您所说的“如果值中的某些元素是,那么我想要匹配的字符串”的意思?

您也可以使用 SortedSet,因为 Cats 为 SortedSet 提供了一个 Foldable 实例,但它不是那么方便:

scala> import cats.implicits._
import cats.implicits._

scala> import scala.collection.immutable.SortedSet
import scala.collection.immutable.SortedSet

scala> (SortedSet.empty[ValidatedNel[String, Double]] ++ values).combineAll
res2: cats.data.ValidatedNel[String,Double] = Valid(3.0)

scala> (SortedSet.empty[ValidatedNel[String, Double]] ++ withSomeBadOnes).combineAll
res3: cats.data.ValidatedNel[String,Double] = Invalid(NonEmptyList(bar, foo))

您还可以对幺半群使用标准的 fold|+| 运算符:

scala> values.fold(Validated.valid(0.0))(_ |+| _)
res4: cats.data.ValidatedNel[String,Double] = Valid(3.0)

总结一下:你不能直接在你的Set上调用combineAll,因为Cats没有为提供Foldable >设置。我建议在任何情况下仔细重新考虑您对 Set 的使用,但如果您决定坚持使用它,您有几个选择:转换为 ListSortedSet 就像我上面的那样,在 Set 上使用标准的 fold,或者最终编写你自己的 Foldable[Set] 或使用来自 alleycats 的那个。

关于scala - 如何对 Set[ValidatedNel[String, Double]] 求和?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56584455/

相关文章:

java - Maven 无法从存储库中的另一个依赖项加载依赖项

Scala 打字 : How to Ensure Numeric Type

Javascript 函数式编程测验

TypeScript 泛型在 Curried 时不适用于以前的函数,如何?

javascript - 分支是柯里化(Currying)的必要特征吗?

scala - 如何使用 IO monad 编写猫的理解力

java - 为什么 start-all.sh 的根本原因是 "failed to launch org.apache.spark.deploy.master.Master: JAVA_HOME is not set"?

scala - 如何将akka http与akka流绑定(bind)?

scala - 减少/折叠幺半群列表但减少器返回任一

scala - 猫-范围内的 `Monad`实例时如何使用for-comprehension?