我所拥有的是List[Validated[NonEmptyList[ErrorType], T]]
,我希望将其扁平化为Validated[NonEmptyList[ErrorType], T]
我的不良尝试是收集所有错误,然后再制作一个新错误。
val errors = validations collect {
case Invalid(errs) => errs.toList
}
if (errors.nonEmpty) Invalid(NonEmptyList.fromListUnsafe(errors.flatten)) else Valid(t)
我已经尝试了foldMap
和traverse
,但是我遇到了问题,我在范围内没有Monoid
,我觉得猫可能会开箱即用在一个班轮。
有些older answers on this kind of question似乎已过时(或者至少我找不到他们所指的功能)。
更新
我已经修好了这个类型。
答案 0 :(得分:1)
要回答您的问题this example uses kind projector compiler plugin for partial application of type parameters。根据您对Scala术语的熟悉程度,这可能不完全合理。基本上它意味着一些Scala方法需要某个形状的参数,并且你必须通过在适当的位置添加一个问号来帮助编译器。
还要确保添加一些导入。
import cats._
import cats.data._
import cats.implicits._
import Validated.{ valid, invalid }
然后给出,
val a = valid[String,Int](1)
val as = List(a)
您可以使用List.sequence
将List[Validated[NonEmptyList[E, T]]]
转换为Validated[E, List[T]]
。
as.sequence[Validated[String,?], Int]
在这种情况下,如果使用单个String作为错误类型,则表示错误类型的字符串将连接在一起形成一个字符串。这是monoid约束来自你提到的
- 它有助于将字符串与字符串连接组合在一起。其他错误类型也可能有效,例如错误类型为List[String]
或List[ErrorType]
,而不是简单的String
。如果要累积错误,请使用某种错误类型的列表
val a = valid[List[String],Int](1)
val b = invalid[List[String], Int]("some".lift[List])
List(a,b).sequence[Validated[List[String],?], Int]
结果
res29: Validated[List[String], List[Int]] = Invalid(List("some"))
上面需要提升操作从String到String列表。
答案 1 :(得分:1)
如果你正在使用sbt-partial-unification或uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"
uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"
编译器标志(你应该使用),你可以使用:
-Ypartial-unification
这是不安全的(只有在验证列表不为空时才有效)。 现在,如果您先构造实例,然后再验证它:
validation.sequence.map(_.head)
你仍然拥有它,你可以直接提供它:
val t: T = ???
val validation: List[Validated[NonEmptyList[ErrorType], T]] =
List(checkQuantities, checkName, checkConsisteny).map(f => f(t))
答案 2 :(得分:1)
我昨天刚刚遇到了类似的问题。这就是我解决它的方式(我使用的是Scala 2.12和Cats 1.1.0):
import cats.Traverse
import cats.data.{NonEmptyList, Validated}
val list: List[Validated[NonEmptyList[ErrorType], T]] = ...
import cats.instances.list._
val validated: Validated[NonEmptyList[ErrorType], List[T]] = Traverse[List].sequence(list)
这不是你想要的,因为这会将结构展平为List[A]
而不是A
。为了将A
展平为相同类型,您可能需要在某处实现Monoid[A]
方法的combine
。