组合Seq [ValidatedNel]的有效值

时间:2017-10-24 23:28:06

标签: scala scala-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]]]

所以,我的第一步是为Semigroup实施Seq[MyString]

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中来准备我的数据...这感觉很奇怪。那么,也许有更好的方法呢?

1 个答案:

答案 0 :(得分:3)

如果您使用Seq以外的任何内容,例如VectorList,则可以sequence

sequence基本上将一个类型构造函数转换为内部。意味着将F[G[A]]变为G[F[A]]。为了实现这一目标,F必须是Traverse,而G必须是Applicative。幸运的是,ValidatedApplicativeListVectorTraverse的实例。

所以最后你的代码应该是这样的:

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团队强烈建议您在使用猫时始终使用此标记,因为它使一切变得更加容易。