liveBook · Manning

Error accumulation

As explained in Functional Programming in Scala, Second Edition

Error accumulation is the combination of multiple computation errors into a single error result instead of stopping at the first error.

Error accumulation combines multiple computation errors into one result instead of stopping at the first failure. Validated gives this behavior a named type, separating it from Either’s fail-fast structure. section 4.4.2

Validated applies accumulation through composable operations:

  • map2 combines two successful values, or merges both errors when both computations are invalid. section 4.4.2
  • traverse and sequence extend the same behavior across lists, using a supplied error-combination function. section 4.4.2
  • The error representation can be a List, Vector, nonempty collection, or another structure with a combination operation. section 4.4.2
enum Validated[+E, +A]:
  case Valid(get: A)
  case Invalid(errors: List[E])
 
  def toEither: Either[List[E], A] =
    this match
      case Valid(a) => Either.Right(a)
      case Invalid(es) => Either.Left(es)
 
  def map[B](f: A => B): Validated[E, B] =
    this match
      case Valid(a) => Valid(f(a))
      case Invalid(es) => Invalid(es)
 
  def map2[EE >: E, B, C](
    b: Validated[EE, B])(
    f: (A, B) => C
  ): Validated[EE, C] =
    (this, b) match
      case (Valid(aa), Valid(bb)) => Valid(f(aa, bb))
      case (Invalid(es), Valid(_)) => Invalid(es)
      case (Valid(_), Invalid(es)) => Invalid(es)
      case (Invalid(es1), Invalid(es2)) => Invalid(es1 ++ es2)
 
object Validated:
  def fromEither[E, A](e: Either[List[E], A]): Validated[E, A] =
    e match
      case Either.Right(a) => Valid(a)
      case Either.Left(es) => Invalid(es)
 
  def traverse[E, A, B](
    as: List[A], f: A => Validated[E, B]
  ): Validated[E, List[B]] =
    as.foldRight(Valid(Nil): Validated[E, List[B]])((a, acc) =>
      f(a).map2(acc)(_ :: _))
 
  def sequence[E, A](vs: List[Validated[E, A]]): Validated[E, List[A]] =
    traverse(vs, identity)

Inspect the Validated definition and its map, map2, and conversion operations. section 4.4.2

How Functional Programming in Scala, Second Edition covers it

How deep it goes
Defines map2, generalizes error combination beyond lists, and extends the pattern through traverse and sequence.
Examples
Uses Validated values, List-based errors, map2, traverse, and sequence as concrete implementation examples.
What it assumes
Assumes familiarity with Either-like success and failure values and functions such as map2, traverse, and sequence.
What you can do after
Apply it via Validated to combine validation results and collect multiple errors across lists.
How it connects
Connects Validated with Either, map2, traverse, sequence, and compositional error representations.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Functional Programming in Scala, Second Edition. The section links point to the parts of the book it draws on.