首页 > 解决方案 > 如何对 Set[ValidatedNel[String, Double]] 求和?

问题描述

我有这个:

Set[ValidatedNel[String, 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 ...

标签: scalafunctional-programmingscala-cats

解决方案


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

一般来说,总结具有实例的元素最直接的方法Monoid是使用combineAll具有实例的事物的方法Foldable——例如 a 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 为 提供了一个Foldable实例SortedSet,但它并不方便:

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)

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


推荐阅读