How to sum a Set[ValidatedNel[String, Double]]?

spa*_*org 3 functional-programming scala scala-cats

I have this:

Set[ValidatedNel[String, Double]] 
Run Code Online (Sandbox Code Playgroud)

and I would like to sum the Doubles in it to get:

ValidatedNel[String, Double]
Run Code Online (Sandbox Code Playgroud)

If some elements in the values are then I would like to have matching strings.

I played with Set.sum and Numeric to no avail...

Here is the test of what I would like to achieve:

  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))
  }
Run Code Online (Sandbox Code Playgroud)

I don't manage to create the validatedNelNumeric...

Tra*_*own 5

首先:在这种情况下使用一个集合有点奇怪(用于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)
Run Code Online (Sandbox Code Playgroud)

然后:

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))
Run Code Online (Sandbox Code Playgroud)

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

您还可以使用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))
Run Code Online (Sandbox Code Playgroud)

您还可以将标准fold|+|运算符用于monoid:

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

总结:由于Cats没有提供for ,因此您不能combineAll直接致电。我建议您在任何情况下都要仔细考虑重新使用,但是如果您决定坚持使用,则可以选择以下几种方法:转换为或像我上面所述的那样,在上使用标准,或者最终自己编写或使用一只来自胡同。SetFoldableSetSetListSortedSetfoldSetFoldable[Set]