In this post I will give a practical introduction to some useful structures for handling failure in functional programming.

One of the most important properties of functional programming is referential transparency and programming with pure functions. This means we can substitute a pure function with its result, for intance if we have the function `def f = 1 + 2`

, we can replace every occurence of `f`

with `3`

and the final evaluation will remain unchanged

This simple idea can lead to difficulties when considering functions which involve side effects, such as reading from external sources or generating random numbers. One example of a side effect is an exception, an imperative programmer might write a function to calculate a square root as:

```
def unsafe_sqrt(a: Double): Double = {
if (a > 0) math.sqrt(a)
else throw new Exception("Can't calculate square root of negative number")
}
```

This compiles fine, however if we wrote this function for an end user and they didn’t look at the implementation they might not know the function can possibly return an exception.

In order to make it clear that a function can fail, we can return a `Try`

:

```
def try_sqrt(a: Double): Try[Double] = {
if (a > 0) Success(math.sqrt(a))
else Failure(throw new Exception("Can't calculate square root of negative number"))
}
```

Now, if someone were to use this function they would be forced to deal with the `Try`

return type and understand that the function can return an exception. Try is actually an algebraic datatype (ADT), an illustrative implementation is:

```
sealed trait Try[+A]
case class Success[+A](a: A) extends Try[A]
case class Failure[+A](exception: Throwable) extends Try[A]
```

This means that a `Try`

can either be a `Success`

or `Failure`

. Learn more about `Try`

in Daniel Westheide’s excellent Neophyte’s Guide to Scala.

Another simple structure to represent computations which may fail is `Option`

, this is an algebraic datatype:

```
sealed trait Option[+A]
case class Some[+A](a: A) extends Option[A]
case class None extends Option[Nothing]
```

In this case, option can either contain a value using the constructor `Some`

, or can represent the absense of a value using `None`

. This provides less information on failure that `Try`

, but nevertheless is sometimes useful. We can re-write the `sqrt`

function to return an optional value

```
def option_sqrt(a: Double): Option[Double] = {
if (a > 0) Some(math.sqrt(a))
else None
}
```

Now, when provide an incorrect argument to the function, we get `None`

as the result.

In real world functional codebases we compose programs from many small functions. Let’s consider the problem of how to apply `def sqrt(a: Double): Option[Double]`

twice. A naive attempt would be to simply compose the functions as we would for the Scala math library:

```
def sqrt_twice = unsafe_sqrt _ compose unsafe_sqrt _
```

The `_`

represents partial application of `unsafe_sqrt`

, if we try to compose the `option_sqrt`

function as in this example we will get a type mismatch. One application of `option_sqrt`

returns a typle `Option[Double]`

, but we need the type `Double`

. Luckily `Option`

has a function defined on it for composing operations like this:

```
def flatMap[A, B](a: Option[A])(f: A => Option[B]): Option[B]
```

We can now use `flatMap`

to compose `option_sqrt`

:

```
def sqrt_twice_option(x: Double): Option[Double] =
option_sqrt(x) flatMap option_sqrt
```

Now we can calculate `sqrt_twice_option(81) = Some(3.0)`

.

We can compose `try_sqrt`

in the same way:

```
def sqrt_twice_try(x: Double): Try[Double] =
try_sqrt(81) flatMap try_sqrt
```

Now, what if we want to compose `option_sqrt`

and `try_sqrt`

. This is not an easy problem in general, however the Scala standard library implements a `toOption`

method on `Try`

values. Hence we can just convert the output of `try_sqrt`

to an `Option`

, however we lose the text from the exception upon failure, which could illuminating in the event of a failure. Let’s consider a more general way to compose the two.

`Option`

and `Try`

are both monads (strictly `Try`

is not a proper monad), which means they are equipped with two methods which satisfy the monad laws. The two methods defined for all monads are:

```
trait Monad[A, M[_]] {
def flatMap[B](f: A => M[B]): M[B]
def pure(a: A): M[A]
}
```

We can define all the functions on `Try`

and `Option`

using these two functions, for instance `map`

:

```
def map[B](f: A => B): M[B] = this.flatMap(a => pure(f(a)))
```

Now, we can use the `map`

function to compose `option_sqrt`

and `try_sqrt`

:

```
def sqrt_twice(a: Double): Try[Option[Double]] = try_sqrt(a) map option_sqrt
```

However, what if we want to apply another function to a value returned by this function:

```
def f(a: Double) = a + 1
sqrt_twice(81) map (_.map(f))
// Success(Some(4.0))
```

We get the correct value, but we have to apply `map`

twice, this seems cumbersome. There is a better way!

The functional programming library cats, short for category, has some built in types for dealing with nesting in a more elegent way. The type `OptionT[F[_], A]`

can be used instead of `F[Option[A]]`

, our `F[_]`

type in this case is `Try[A]`

```
import cats.implicits._
import cats.data.OptionT
def sqrt_twice_trans(a: Double): OptionT[Try, Double] =
OptionT.fromOption[Try](option_sqrt(a)) flatMap (b => OptionT.liftF(try_sqrt(b))
```

`OptionT`

provides the function `fromOption`

to transform the result of the `option_sqrt`

function into the `OptionT`

monad. The function `liftF`

is used to lift any monad, in this case `Try`

into the `OptionT`

monad. This compiles and we if we now try to apply the function `def f(a: Double) = a + 1`

to the result of this function we only need a single call to `map`

. This is because `OptionT`

is also a monad:

```
sqrt_twice_trans(81) map f
// OptionT(Success(Some(4.0)))
```

This may seem like quite a lot of effort to remove a call to map, but removing unecessary duplication can help with readability of code, and enable bugs to be spotted earlier. The code has been assembled in a Github gist.

For attribution, please cite this work as

Law (2017, Jan. 4). Bayesian Statistics and Functional Programming: Using Monads for Handling Failures and Exceptions. Retrieved from https://jonnylaw.rocks/posts/2017-01-04-FailureInFunctionalProgramming/

BibTeX citation

@misc{law2017using, author = {Law, Jonny}, title = {Bayesian Statistics and Functional Programming: Using Monads for Handling Failures and Exceptions}, url = {https://jonnylaw.rocks/posts/2017-01-04-FailureInFunctionalProgramming/}, year = {2017} }