-
-
Save fmonniot/058d73d7a951a6305d1dc6fd9e4550ca to your computer and use it in GitHub Desktop.
Using Cats for error validation with error accumulation. Comparison with Scalactic: https://gist.github.com/atamborrino/5d2780512ea3eccc98bccd4557f7207e
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
object TestCats { | |
import cats._ | |
import cats.data._ | |
import cats.instances.future._ | |
import cats.syntax.either._ | |
import cats.syntax.cartesian._ | |
import cats.instances.list._ | |
import cats.syntax.traverse._ | |
trait Error | |
type Errors = NonEmptyList[Error] | |
type Result[A] = Either[Errors, A] | |
// Result | |
case object AnError extends Error | |
def aOrError: Result[String] = "a".asRight | |
def bOrError: Result[Int] = NonEmptyList.of(AnError).asLeft | |
type ResultWithErrorAcc[A] = Validated[Errors, A] // to avoid writing a lambda type | |
val res: Result[(String, (String, Int), List[String])] = for { | |
a <- aOrError | |
b <- (aOrError.toValidated |@| bOrError.toValidated).tupled.toEither | |
c <- { | |
List(aOrError.toValidated, aOrError.toValidated) | |
.sequence[ResultWithErrorAcc, String] // does not compile without explicit type | |
.toEither | |
} | |
} yield (a, b, c) | |
// Future Result | |
import scala.concurrent._ | |
import scala.concurrent.ExecutionContext.Implicits.global | |
def futAOrError: Future[Result[String]] = Future.successful("a".asRight) | |
def futBOrError: Future[Result[Int]] = Future.successful(NonEmptyList.of(AnError).asLeft) | |
type FutResultWithErrorAcc[A] = Future[Validated[Errors, A]] // to avoid writing a lambda type | |
implicit val FutValidatedApplicative = Applicative[Future].compose[ResultWithErrorAcc] | |
val res2 = for { | |
a <- EitherT(futAOrError) | |
b <- EitherT { | |
FutValidatedApplicative.product(futAOrError.map(_.toValidated), futBOrError.map(_.toValidated)) | |
.map(_.toEither) | |
} | |
c <- EitherT { | |
List(futAOrError.map(_.toValidated), futAOrError.map(_.toValidated)) | |
.sequence[FutResultWithErrorAcc, String] // does not compile without explicit type | |
.map(_.toEither) | |
} | |
} yield (a, b, c) | |
val res3: Future[Result[(String, (String, Int), List[String])]] = res2.value | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment