Grokking Applicative Validation
Tags: fsharp, functional, programming, grokking
Published: 2021-04-16 13:28:56

---
title: Grokking Applicative Validation
published: true
description: 
tags: fsharp, functional, programming, grokking
series: Grokking Functional Programming
//cover_image: https://direct_url_to_image.jpg
---

Previously in [Grokking Applicatives](https://dev.to/choc13/grokking-applicatives-44o1) we discovered Applicatives and more specifically invented the `apply` function. We did this by considering the example of validating the fields of a credit card. The `apply` function allowed us to easily combine the results we obtained from validating the number, expiry and CVV individually into a `Result<CreditCard>` that represented the validation status of an entire `CreditCard`. You might also remember we somewhat glossed over the error handling when multiple fields were invalid. We took the easy road and just returned the first error that occurred. 

# An unhappy customer 😡
In the spirit of agile we decided to ship our previous implementation, because, well it was better than nothing. A short while later, customers start complaining. All the complaints are along these lines.

> "I entered my credit card details on your site and it took three attempts before it was finally accepted. I submitted the form and each time it gave me a new error. Why couldn't you tell me about all the errors at once?"

To see this more clearly consider a customer that enters the following data, in JSON form.

```json
{
    “number”: “a bad number”,
    “expiry”: “invalid expiry”,
    “cvv”: “not a CVV”
}
```

The first time they submit the form they get an error like `”’a bad number’ is not a valid credit card number”`. So they fix that and resubmit. Then they get a message like `”’invalid expiry’ is not a valid expiry date”`. So they fix that and submit a third time and still receive an error along the lines of `”’not a CVV’ is not a valid CVV”`. Pretty annoying!

We should be able to do better and return all of the errors at once. We even previously pointed out that all of the field level validation functions were independent of each other. So there was no good reason not to run all of the functions and aggregate the errors if there were any, we were just being lazy! 

# A better validation Applicative 💪
Let's start by updating the signature of `validateCreditCard` to signify our new desire to return all the validation errors that we find.

```fsharp
let validateCreditCard (card: CreditCard): Result<CreditCard, string list>
```

The only change here is that we’re now returning a `list` of error messages rather than a single one. How should we update our implementation to satisfy this new signature?

Let’s return to the `apply` function that we defined before and see if we can just fix it there. It would be very nice if all we had to do was modify `apply` and leave `validateCreditCard` otherwise unchanged.

For reference here’s the `apply` function that we wrote last time, the one that returns the first error it encounters. 

```fsharp
let apply a f =
    match f, a with
    | Ok g, Ok x -> g x |> Ok
    | Error e, Ok _ -> e |> Error
    | Ok _, Error e -> e |> Error
    | Error e1, Error _ -> e1 |> Error
```

We can see from this that it’s only the final case where we have multiple errors to deal with and so it’s only there that we need to fix things. The simplest fix is to just concatenate both errors. This has the effect of building up a list of errors each time we call `apply` with invalid data. Let’s see what that looks like then. 

```fsharp
let apply a f =
    match f, a with
    | Ok g, Ok x -> g x |> Ok
    | Error e, Ok _ -> e |> Error
    | Ok _, Error e -> e |> Error
    | Error e1, Error e2 -> (e1 @ e2) |> Error
```

That was easy, we just used `@` to concatenate the two lists in the case where both sides were `Error`. Everything else remained the same.

Let’s walk through validating the credit card step-by-step with the example of the bad data that the customer was supplying earlier. First we call `Ok (createCreditCard) |> apply (validateNumber card.Number)`. This hits the third case of the pattern match in `apply` because `f` is `Ok`, but the argument `a` is `Error`. That returns us something like an `Error [ “Invalid number” ]`, but whose type is still `Result<string -> string -> CreditCard, string list>`. 

We then pipe this like `|> apply (validateExpiry card.Expiry)`. This hits the final case in the pattern match because now both `f` and `a` are `Error`. This means the `@` operator is used to concat the errors together to create something like `Error [ “Invalid expiry”; “Invalid number” ]`. The type of which is now `Result<string -> CreditCard, string list>` because we now just need to supply a CVV to finish creating the `CreditCard`. 

So in the final step we do exactly that and pipe this result like `|> apply (validateCvv card.Cvv)`. Just like the last step we hit the case where both `f` and `a` are `Error` and so we concat them. Now we’ve got something with the type `Result<CreditCard, string list>` as we wanted with a value like `Error [ “Invalid CVV”; “Invalid expiry”; “Invalid number” ]`. 

# A small compile time error
You might have spotted that we’ve actually changed the type of the `apply` function now. By using the `@` operator F# has inferred that the errors must be a `list`. So now the signature of `apply` is `Result<T, E list> -> Result<T -> V, E list> -> Result<V, E list>`.

We now have an `apply` that works for `Result<T, E list>`. That is, it works for any results where the errors are contained in a `list`, rather than being single values like a `string`. There are a couple of interesting points to make about this:
1. The errors in the list can be any type, providing they’re all of the same type. 
1. All of our validated results must now have a `list` of errors if we want to use them with `apply`.

Point 1 is useful because it allows us to model our errors in more meaningful ways than just using strings. Although for the rest of this post we’ll keep using `string` in order to keep it simple. Modelling errors deserves a blog post of its own. 

Point 2 however causes us a little problem we have to solve here. Our original field level validation functions are still returning `Result<string, string>` so they no longer work with our new version of `apply`. 

We have two choices when it comes to fixing this issue. We could keep the functions as they are and transform their outputs by wrapping the error, if it exists, of the result in a `list`. Which might look something like this. 

```fsharp
let validateCreditCard (card: CreditCard): Result<CreditCard, string list> =
    let liftError result =
        match result with
        | Ok x -> Ok x
        | Error e -> Error [ e ]
    Ok (createCreditCard)
    |> apply (card.Number |> validateNumber |> liftError)
    |> apply (card.Expiry |> validateExpiry |> liftError)
    |> apply (card.Cvv |> validateCvv |> liftError)
```

The other choice is to update those field validation functions so that they return `Result<string, string list>` as required. It might be tempting to take the first choice and if we had no control over those functions we’d have to do that. However, by letting those field level functions return a list we give them the flexibility to do more complex validation and potentially indicate multiple errors. 

For instance the `validateNumber` function could indicate both a problem with the length and the presence of invalid characters like this. 

```fsharp
let validateNumber number: Result<string, string list> =
    let errors = 
        if String.length num > 16 then
            [ "Too long" ]
        else
            []
    let errors = 
        if num |> Seq.forall Char.IsDigit then
            errors
        else 
            "Invalid characters" :: errors

    if errors |> Seq.isEmpty then
        Ok num
    else
        Error errors
```

Using `Result<T, E list>` throughout gives us a more composable and flexible api that allows us to refactor the errors returned from those functions in the future without affecting the rest of the program. 

So given that they’re functions in our domain, then we’ll take that approach. Let’s give that a try and see what it looks like all together when using this new version of `apply`.

```fsharp
let validateNumber num: Result<string, string list> =
    if String.length num > 16 then
        Error [ “Too long” ]
    else
        Ok num

let validateExpiry expiry: Result<string, string list> =
    // validate expiry and return all errors we find

let validateCvv cvv: Result<string, string list> =
    // validate cvv and return all cvv errors we find

let validateCreditCard (card: CreditCard): Result<CreditCard, string list> =
    Ok (createCreditCard)
    |> apply (validateNumber card.Number)
    |> apply (validateExpiry card.Expiry)
    |> apply (validateCvv card.Cvv)
```

Lovely job! Apart from a couple of small changes to lift the errors up into lists within `validateNumber` etc the rest has stayed the same. In particular, the body of `validateCreditCard` is completely unchanged.

# Do I have to use list for the errors
The only requirement we’ve placed on the error type is that we can use the `@` operator to concat the errors together. So as long as the errors are concat-able then we can use a different type here. The fancy category theory name for this is a semi-group. A semi-group is anything that has at least a concat operator defined for it. A common type to use here is a `NonEmptyList`, because we know that if the result is an `Error` then they’ll be at least one item in the list. 

# A tale of two applicatives 📗
We’ve seen two implementations of `apply` for `Result` now. Can we have both? Unfortunately not really, at least not both defined in the `Result` module of F#. In order to do this F# would have to be able to decide which one to use based on whether the error type supported concat, which might not even be obvious without an explicit type annotation. Even then we might get undesired results because strings support concat, but it’s unlikely we want to concat the individual error messages into one long string. 

How should we decide which one is correct then? Well, we don’t have to. We can define another type called `Validation` which has a `Success` case and a `Failure` case, similar to `Ok` and `Error` for `Result`. The difference is that for `Validation` we can define `apply` using the version we’ve created in this post which accumulates errors and for `Result` use the `apply` function that short circuits and returns the first error, that we saw in the last post. Luckily for us the excellent [FSharpPlus](https://fsprojects.github.io/FSharpPlus/) library has already done exactly that. 

# What did we learn 🧑‍🏫
We’ve seen that applicatives are a great tool to have at our disposal when writing validation code. They allow us to write validation functions for each field and then easily compose these to create functions for validating larger structures made up of those fields. 

We’ve also seen that whilst applicative computations are usually independent of each other there’s nothing to guarantee that a particular implementation of `apply` will make full use of this. Specifically, when working with validation we want to make sure that `apply` accumulates all errors and so we should make sure to use a type like `Validation` from FSharpPlus to get this behaviour.