Skip to content

Instantly share code, notes, and snippets.

@fmonniot
Forked from atamborrino/TestCats.scala
Created February 22, 2017 14:13
Show Gist options
  • Save fmonniot/058d73d7a951a6305d1dc6fd9e4550ca to your computer and use it in GitHub Desktop.
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
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