0

I have written this code

def valid1() : Validated[List[String], Boolean] = {...}
def valid2() : Validated[List[String], Boolean] = {...}
def valid3() : Validated[List[String], Boolean] = {...}
def valid4() : Validated[List[String], Boolean] = {...}
val consolidated = valid1 |@| valid2 |@| valid3 |@| valid4
consolidated.map{_ && _ && _ && _} match {
  case Valid(true) => // do something
  case Invalid(errorList) => // do something
}

Instead of doing |@| on each intermediate validation and doing a && inside the map... can I write it in a simpler way? I guess individually trying to do |@| and then && makes the code look a little scary. (sorry I am not a jedi yet)

Knows Not Much
  • 30,395
  • 60
  • 197
  • 373

1 Answers1

2

You could use sequence (or sequenceU).

import cats.data.{NonEmptyList, Validated}
import cats.implicits._
// import cats.syntax.reducible._
// import cats.syntax.traverse._

val valids = NonEmptyList.of(valid1, valid2, valid3, valid4)

val consolidated: Validated[List[String], Boolean] =
  valids.sequenceU.map(_.reduceLeft(_ && _))

Validated[List[String], Boolean] is sort of a strange type as it can represent two invalid/false cases : Invalid(messagesList) and Valid(false). As you are only pattern matching Valid(true) (not Valid(false)), this can probably also be modelled as Validated[List[String], Unit].

// import cats.syntax.foldable._

val consolidated2: Validated[List[String], Unit] =
  valids.traverseU_(_.ensure("was false" :: Nil)(identity))

consolidated2.fold(
  errorList => // do something 
  , _ => // do something
)

For the compiler error: You probably have another dependency using an older version of Cats. Cats dropped the Xor data type in favour of Either in version 0.8.0.

Peter Neyens
  • 9,770
  • 27
  • 33