FP for Beginners - I - ScalaZ Validation
by Raúl Raja Martínez
- •
- April 27, 2015
- •
- scala• scalaz• functional programming• validation• error handling• code tutorials
- |
- 8 minutes to read.

What is FP for Beginners
?
FP for Beginners is a series of posts in which we explain functional programming (FP) patterns in a clear way for folks getting started with FP and Scala.
We will feature some of the most useful FP abstractions and utilities introduced in ScalaZ, Shapeless, and other FP- and Type-centric libraries that can help us solve common problems in our programming life.
The case for ScalaZ
We believe FP is important and ScalaZ is a great example of a library that allows for powerful abstractions that we can use to solve common problems with succinct code.
There is a world beyond map
, flatMap
, filter
, and basic exposure to the Scala collections and standard library.
After all, many newcomers to Scala see FP as the next frontier and not the end. FP is among the most attractive selling points of Scala, along with Java interoperability.
Now, take a breath. We are going to take it easy and show you real-world examples that you probably face frequently, even if you are new to Scala.
Let’s get started with Validation
, a great abstraction to handle errors, exceptions, and success/failure cases.
Validation
Validation
can be either a Success
or a Failure
.
Much like how Try
, Option
or Either
in the standard Scala lib works, Validation
is also a container of sorts that lets you obtain information and branch your program logic based on the success or failure of evaluating expression.
Model
We are going to teach by example. First, we’ll show you a simple requirement and evolve its implementation to make it more flexible and robust.
Requirement
:
Provide a method to convert from a collection of String
to a collection of Int
.
Our first implementation looks like this:
def toInts(maybeInts : List[String]) : List[Int] = {
maybeInts map («_.toInt»)
}
»_.toInt|<code>_.toInt</code> is a lambda that is executed on each one of the elements in <code>maybeInts</code>. If an exception is thrown at any point it will not be captured and it will interrupt execution of <code>toInts</code>«
That method signature is full of assumptions. It’s only by looking at the implementation that we know what is actually going on. If we did not have access to the impl sources we would think that:
- It may be discarding strings that can’t be represented as numbers.
- It may be bailing with a runtime exception the very first time it encounters an invalid number.
- It may simply be ignoring invalid numbers altogether and just returning valid ones.
Neither of them is obvious to the call site.
We can improve error handling here by rewriting its signature and implementation to use Try
.
Try
is part of the standard library and wraps the evaluation of any expression into Success
or Failure
.
Let’s introduce Try
in the return type and impl.
def toInts(maybeInts : List[String]) : Try[List[Int]] = {
«Try(maybeInts map (_.toInt))»
}
»Try|Try let's you execute a function <code>f: => R</code> and returns either a <code>Success[R]</code> or a <code>Failure[Throwable]</code> with any non fatal exceptions resulting from evaluating <code>f</code>«
That’s a little better. At this point at least it won’t bail with an uncaught exception and we can handled both Success
and Failure
.
val result : Try[List[Int]] = toInts(List("1", "2", "3"))
result match {
case Success(numbers) => println(numbers)
case Failure(ex) => println(ex)
}
Since Try
is a monad and includes flatMap
, we can even for comprehend over it assuming success and do further transformations in its content.
val «transformedResult» : Try[List[Int]] = for {
x <- result
} yield x map(_ * 2)
»transformedResult|<code>Success(List(2, 4, 6))</code>«
This still only supports a fail fast
strategy and it’s still not possible to do error accumulation. How will we know which strings can’t be turned into numbers?
Enter ValidationNel
.
ValidationNel[E, A]
is a type alias for a Validation[NonEmptyList[E], A]
. It brings the semantics of error accumulation over validation and returns all errors found in a non-empty list.
Let’s break down our function and its implementation to validate all cases and reduce the list of validations into a single result where we can access either the successful value or all errors found when parsing.
def toInts(maybeInts : List[String]): ValidationNel[Throwable, List[Int]] = {
val validationList = maybeInts map { s =>
Validation.«fromTryCatchNonFatal»(s.toInt :: Nil).toValidationNel
}
validationList reduce («_ +++ _»)
}
»fromTryCatchNonFatal|From the official API docs: <i>Extractor of non-fatal Throwables. Will not match fatal errors like VirtualMachineError (for example, OutOfMemoryError and StackOverflowError, subclasses of VirtualMachineError), ThreadDeath, LinkageError, InterruptedException, ControlThrowable.</i>«
»+++|Sums up values inside validation, if both are success or failure. Returns first failure otherwise.«
Well, this is cool! We can now access both successes and failures. Let see what this looks like in the REPL:
Succeeding
scala> toInts(List("1", "2", "3"))
res1: scalaz.ValidationNel[Throwable,List[Int]] = Success(List(1, 2, 3))
Failing
scala> toInts(List("1", "2", "3", "x", "z"))
res2: scalaz.ValidationNel[Throwable,List[Int]] =
Failure(
NonEmptyList(
java.lang.NumberFormatException: For input string: "x",
java.lang.NumberFormatException: For input string: "z"))
We can now write our own function to validate transformations in lists. But now this is where it gets more interesting.
Can we further generalize this beyond simple String -> Int
conversions?
Let’s rewrite toInts
as a generic validation function to accept anything that can be folded over along with a function for transforming the data inside the containers.
def validate[F[_] : Foldable, A, B : Monoid]
(in : F[A])
(out : A => B): ValidationNel[Throwable, B] = {
in foldMap (a => Validation.fromTryCatchNonFatal[B](out(a)).toValidationNel)
}
Now it’s fairly simple to define toInts
in terms of validate
def toInts(maybeInts : List[String]): ValidationNel[Throwable, List[Int]] =
validate(maybeInts)(_.toInt :: Nil)
An extra advantage is that we can now operate over anything that is Foldable
not just List
in typesafe way
scala> validate(Option("1"))(_.toInt)
res0: scalaz.ValidationNel[Throwable,Int] = Success(1)
scala> validate(Option("x"))(_.toInt)
res1: scalaz.ValidationNel[Throwable,Int] = Failure(NonEmptyList(java.lang.NumberFormatException: For input string: "x"))
scala> validate(Vector("1"))(_.toInt)
res7: scalaz.ValidationNel[Throwable,Int] = Success(1)
Let’s dig into the function definition so we understand what is going on behind the scenes.
Signature:
def validate[«F[_]» «: Foldable», «A», «B : Monoid»]
(«in : F[A]»)
(«out : A => B»): ValidationNel[Throwable, B]
»F[_]|<code>F</code> here is a type constructor that represents anything that may wrap <code>A</code>«
»:Foldable|<code>:Foldable</code> on <code>F[_]</code> constrains all <code>F</code> to have an implicit instance of Foldable for the type that we want to invoke <code>foldMap</code> over.«
»A|<code>A</code> is the actual initial data inside <code>F</code> that can be folded over«
»B|<code>B: Monoid</code> brings in an implicit <code>Monoid</code> instance for <code>B</code>. In order to fold over <code>B</code> given we wrap the result in <code>ValidationNel</code> we need to provide an instance that includes <code>append</code> and knows how to sum <code>ValidationNel[B, E] +++ ValidationNel[B, E]</code>.<br><code>Validation[B, E]</code> can act as a monoid as long as his <code>Success</code> and <code>Failure</code> container types include <code>Monoid</code> instances as well.«
»in : F[A]|The container that can be folded over«
»out : A => B|A function that we can use to transform from <code>A</code> to <code>B</code> and can potentially throw an exception when doing so«
Body:
in «foldMap» (a => Validation.fromTryCatchNonFatal[B](out(a)).toValidationNel)
»foldMap|applies <code>out</code> on each element folding the results on themselves and sums on each iteration«
We wrap all evaluations of out(a)
on Validation.fromTryCatchNonFatal[B]
to ensure that all exceptions resulting from the transformation are properly captured.
Finally we invoke toValidationNel
to lift the validation
resulting from the transformation so that exceptions can be accumulated in the NonEmptyList
in case of failure
Our validation function now supports error accumulation and it’s generic enough so that it can be applied over any containers with arbitrary transformations.
ScalaZ also provides multiple utils to lift any value to Validation
and ValidationNel
scala> 1.successNel
res3: scalaz.ValidationNel[Nothing,Int] = Success(1)
scala> 1.failureNel
res4: scalaz.ValidationNel[Int,Nothing] = Failure(NonEmptyList(1))
scala> 1.success
res5: scalaz.Validation[Nothing,Int] = Success(1)
scala> 1.failure
res6: scalaz.Validation[Int,Nothing] = Failure(1)
Conclusion
Validation is isomorphic to Either
or \/
, but unlike those it has the advantage of allowing error accumulation
instead of the default fail fast strategy of other types commonly used for error handling.