如何将一系列猫的ValidatedNel值平铺

21

我需要将一系列的cats.data.ValidatedNel[E, T]值压缩为单个的ValidatedNel值:

val results: Seq[cats.data.ValidatedNel[E, T]] = ???

val flattenedResult: cats.data.ValidatedNel[E, T]

我可以这样做:
import cats.std.list._, cats.syntax.cartesian._

results.reduce(_ |@| _ map { case _ => validatedValue })

但是我想知道是否存在预定义的库方法。

1个回答

29

这取决于您想如何组合它们(在您的问题中,validatedValue是什么?)

import cats.data.{Validated, ValidatedNel}
import cats.implicits._

val validations1 = List(1.validNel[String], 2.valid, 3.valid)
val validations2 = List(1.validNel[String], "kaboom".invalidNel, "boom".invalidNel)

如果你想要合并 T,你可以使用 Foldable.combineAll,它使用一个 Monoid[T]

val valSum1 = validations1.combineAll 
// Valid(6)
val valSum2 = validations2.combineAll 
// Invalid(OneAnd(kaboom,List(boom)))

如果您想获取一个ValidationNel[String, List[T]],可以使用Traverse.sequence:
val valList1: ValidatedNel[String, List[Int]] = validations1.sequence
// Valid(List(1, 2, 3))
val valList2: ValidatedNel[String, List[Int]] = validations2.sequence
// Invalid(OneAnd(kaboom,List(boom)))

如果你不关心结果(看起来是这种情况),你可以使用Foldable.sequence_

val result1: ValidatedNel[String, Unit] = validations1.sequence_
//  Valid(())
val result2: ValidatedNel[String, Unit] = validations2.sequence_
// Invalid(OneAnd(kaboom,List(boom)))

validations1.sequence_.as(validatedValue) // as(x) is equal to map(_ => x)

很抱歉,原问题中的s(现在是validatedValue)是一个正在验证的值,即T - Tvaroh
2
看起来 combineAll 是我需要的。顺便说一下,我需要在我的 Seq 上添加 .toList 调用。 - Tvaroh
@Tvaroh 是的,对于 Seq,cats 没有类型类实例,因此您需要转到 ListVector - Peter Neyens
根据你获取 List[ValidatedNel[String, T]] 的方式,你可以通过使用 foldMap(f)traverseU(f)traverseU_(f) 替换上述函数。 - Peter Neyens
如果您使用 as,则会丢弃结果(Validated 中的 List[T]),因此您可以使用 sequence_ / sequenceU_(在 Validated 中返回 Unit)。由于 Validated 是类型 F[_, _],如果您使用 sequence_,Scala 无法自行推断出类型,因此您可以使用 sequenceU_,它使用一些技巧为您推断类型。但是,这将在2.12中得到修复(请参见此PR)。同时,您可以使用此编译器插件,在这种情况下,您可以使用 sequence_ - Peter Neyens
sequenceU 和 traverseU 在 cats 1.0 中被删除了。然而,如上所述,-Ypartial-unification 和 sequence 仍应该可用。 - RikardA

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接