United Kingdom: +44 (0)208 088 8978

The Option module: map vs bind

Dragos takes a look at map and bind, both found within the Option module

We're hiring Software Developers

Click here to find out more

Introduction

In a previous blog post, we ventured into the intriguing world of the Option module, offering but a fleeting glimpse of Option.map and none of its close companion, Option.bind. In this blog post, I will take the opportunity to talk a bit more about the Option.bind function and show you how helpful it can be when dealing with optional values.

What are they?

Option.map

A higher-order function that allows us to apply a given function to the payload inside an option. It takes an optional value, applies the provided function to its inner value if it is Some and returns the transformed value wrapped back in the option. If the input is None the function does nothing and returns None.

The function signature is as follows:

('T -> 'U) -> 'T option -> 'U option

We give it a function ('T -> 'U) followed by the option we wish to transform with that function ('T option) and it returns an option but with the altered value wrapped inside ('U option)

Option.bind

Let's look at the signature first:

('T -> 'U option) -> 'T option -> 'U option

While the behaviour seems similar, the transformation (also called binding) process is handled differently, the binding process returns an Option value instead of just the value.

The difference

Option.bind is used when you want to chain multiple operations that return options together; each operation might succeed (returning Some value) or fail (returning None). The chain will "break" after the first None as every operation after it will use None with every operation not doing any processing. This process is similar to Railway Oriented Programming.

Let's think in which cases Option.bind might be useful. Imagine you need to find the middle name of the author by looking at the sequel of a book, but we don't know if that book has a sequel or that the author of that sequel book has a middle name, in that case we need to use Option when representing them in our code.

The flow:

  • Find the sequel (Option)
  • Find the middle name (Option)
let getMiddleNameFromSequel (book:Book) = 
    let middleName = 
        book.Sequel
        |> Option.bind (fun s -> s.Author.MiddleName)

    match middleName with
    | Some name -> $"The middle name is: {name}"
    | None -> "Cannot find the middle name"

let author1 = {
    MiddleName = Some "John"
}

let sequelBook = {
    Sequel = None
    Author = author1
}

let book1 = {
    Sequel = Some sequelBook
    Author = author1
}

In this part

 |> Option.bind (fun s -> s.Author.MiddleName)

If you use map and not bind, you might end up with option<option<string>> which would be quite unpleasant to handle.

Conclusion

In this blog post we looked at Option.map and Option.bind and tried to understand their difference and when to use which. Again, I would like to recommend "Stylish F# 6" by Kit Eason which provides more details about handling missing data.

I hope you found this blog post useful 🙂 More stuff about the Option module might soon follow!