如何映射 ValidationNel 的失败?

How to map on failure of ValidationNel?

learned Validation 有方法 :-><-: 来映射成功和失败。

scala> val failure: Validation[String, Unit] = "xxx".failure
failure: scalaz.Validation[String,Unit] = Failure(xxx)

scala> failure.<-:("!!!" + _)
res17: scalaz.Validation[String,Unit] = Failure(!!!xxx)

很遗憾 <-: 不存在 ValidationNel:

scala> val failure: ValidationNel[String, Unit] = "xxx".failureNel
failure: scalaz.ValidationNel[String,Unit] = Failure(NonEmptyList(xxx))

scala> failure.<-:(nel => nel + "!!!")
<console>:15: error: value <-: is not a member of scalaz.ValidationNel[String,Unit]
          failure.<-:(nel => nel + "!!!")

有趣的是,如果我将 may failure 定义为 Validation[NonEmptyList[String], Unit],它确实可以编译。

现在我想知道是否有另一种方法可以将 <-: 用于 ValidationNel

是的,您无法为 ValidationNel 构造一个 Bifunctor 实例,但 ValidationNel 实际上只是 Validation[NonEmptyList[?], ?] 的类型别名,而且如您所知,它确实有一个双函子实例。如果您将值的类型从 ValidationNel 强制转换为 Validation,事情就会开始起作用:

scala> import scalaz._, Scalaz._
import scalaz._
import Scalaz._

scala> val failure: Validation[String, Unit] = "xxx".failure
failure: scalaz.Validation[String,Unit] = Failure(xxx)

scala> failure.<-:("!!!" + _)
res0: scalaz.Validation[String,Unit] = Failure(!!!xxx)

scala> val failure: ValidationNel[String, Unit] = "xxx".failureNel
failure: scalaz.ValidationNel[String,Unit] = Failure(NonEmptyList(xxx))

scala> failure.<-:("!!!" <:: _)
<console>:15: error: value <-: is not a member of scalaz.ValidationNel[String,Unit]
              failure.<-:("!!!" <:: _)
                      ^

scala> val failure2: Validation[NonEmptyList[String], Unit] = failure
failure2: scalaz.Validation[scalaz.NonEmptyList[String],Unit] = Failure(NonEmptyList(xxx))

scala> failure2.<-:("!!!" <:: _)
res2: scalaz.Validation[scalaz.NonEmptyList[String],Unit] = Failure(NonEmptyList(!!!, xxx))

但是,您也可以在验证时调用 leftMap 方法:

scala> failure2.leftMap("!!!" <:: _)
res3: scalaz.Validation[scalaz.NonEmptyList[String],Unit] =      Failure(NonEmptyList(!!!, xxx))

scala> failure.leftMap("!!!" <:: _)
res4: scalaz.Validation[scalaz.NonEmptyList[String],Unit] = Failure(NonEmptyList(!!!, xxx))

或者用"swapped"交换失败和成功,将交换后的值右映射,然后再交换回来:

scala> failure.swapped(_ :-> ("!!!" <:: _))
res5: scalaz.Validation[scalaz.NonEmptyList[String],Unit] = Failure(NonEmptyList(!!!, xxx))