组合 Seq[ValidatedNel] 的有效值
Combine valid values of Seq[ValidatedNel]
我有以下情况:
case class MyString(str: String)
val val1: ValidatedNel[String, MyString] = MyString("valid1").validNel
val val2: ValidatedNel[String, MyString] = MyString("valid2").validNel
val val3: ValidatedNel[String, MyString] = "invalid".invalidNel
val vals = Seq(val1, val2, val3)
//vals: Seq[cats.data.Validated[cats.data.NonEmptyList[String],MyString]] = List(Valid(MyString(valid)), Invalid(NonEmptyList(invalid)))
最后,我希望能够对结果执行 match
,并得到所有错误或所有有效值作为一个序列。
我的问题是:如何将Seq[Validated[NonEmptyList[String],MyString]]
转换成Validated[NonEmptyList[String],Seq[MyString]]]
所以,我的第一步是为 Seq[MyString]
实施 Semigroup
:
implicit val myStringsAdditionSemigroup: Semigroup[Seq[MyString]] = new Semigroup[Seq[MyString]] {
def combine(x: Seq[MyString], y: Seq[MyString]): Seq[MyString] = x ++ y
}
...有效:
Seq(val1, val2).map(_.map(Seq(_))).reduce(_ |+| _)
//res0: cats.data.Validated[cats.data.NonEmptyList[String],Seq[MyString]] = Valid(List(MyString(valid1), MyString(valid2)))
但我需要通过将所有有效值包装在 Seq
中来准备我的数据...这感觉很奇怪。那么,也许有更好的方法来做到这一点?
如果您使用 Seq
以外的其他任何东西,例如 Vector
或 List
,您可以 sequence
它。
sequence
基本上是将类型构造函数从里到外翻转过来。意思是将 F[G[A]]
变成 G[F[A]]
。为此,F
需要是 Traverse
,G
需要是 Applicative
。幸运的是,Validated
是 Applicative
而 List
或 Vector
是 Traverse
.
的实例
所以最后你的代码应该是这样的:
import cats.implicits._
val validatedList: Validated[NonEmptyList[String],List[MyString]]] =
vals.sequence
注意:如果这不适合你,你可能需要启用partial-unification
。
启用 partial-unification
的最简单方法是添加 sbt-partial-unification
plugin.
如果您使用的是 Scala 2.11.9 或更新版本,您还可以简单地添加编译器标志:
scalacOptions += "-Ypartial-unification"
我们 cats
团队强烈建议您在使用猫时始终打开此标志,因为它使一切变得容易得多。
我有以下情况:
case class MyString(str: String)
val val1: ValidatedNel[String, MyString] = MyString("valid1").validNel
val val2: ValidatedNel[String, MyString] = MyString("valid2").validNel
val val3: ValidatedNel[String, MyString] = "invalid".invalidNel
val vals = Seq(val1, val2, val3)
//vals: Seq[cats.data.Validated[cats.data.NonEmptyList[String],MyString]] = List(Valid(MyString(valid)), Invalid(NonEmptyList(invalid)))
最后,我希望能够对结果执行 match
,并得到所有错误或所有有效值作为一个序列。
我的问题是:如何将Seq[Validated[NonEmptyList[String],MyString]]
转换成Validated[NonEmptyList[String],Seq[MyString]]]
所以,我的第一步是为 Seq[MyString]
实施 Semigroup
:
implicit val myStringsAdditionSemigroup: Semigroup[Seq[MyString]] = new Semigroup[Seq[MyString]] {
def combine(x: Seq[MyString], y: Seq[MyString]): Seq[MyString] = x ++ y
}
...有效:
Seq(val1, val2).map(_.map(Seq(_))).reduce(_ |+| _)
//res0: cats.data.Validated[cats.data.NonEmptyList[String],Seq[MyString]] = Valid(List(MyString(valid1), MyString(valid2)))
但我需要通过将所有有效值包装在 Seq
中来准备我的数据...这感觉很奇怪。那么,也许有更好的方法来做到这一点?
如果您使用 Seq
以外的其他任何东西,例如 Vector
或 List
,您可以 sequence
它。
sequence
基本上是将类型构造函数从里到外翻转过来。意思是将 F[G[A]]
变成 G[F[A]]
。为此,F
需要是 Traverse
,G
需要是 Applicative
。幸运的是,Validated
是 Applicative
而 List
或 Vector
是 Traverse
.
所以最后你的代码应该是这样的:
import cats.implicits._
val validatedList: Validated[NonEmptyList[String],List[MyString]]] =
vals.sequence
注意:如果这不适合你,你可能需要启用partial-unification
。
启用 partial-unification
的最简单方法是添加 sbt-partial-unification
plugin.
如果您使用的是 Scala 2.11.9 或更新版本,您还可以简单地添加编译器标志:
scalacOptions += "-Ypartial-unification"
我们 cats
团队强烈建议您在使用猫时始终打开此标志,因为它使一切变得容易得多。