Chain functions using Option type - Functional Programming

24 July 2022οΌ»updatedοΌ½

β€’

5 min read

β€’ Functional programming

The most interesting property of Functional Programming is composition. The Option type allows composing small functions to form a bigger function. Since every function is pure, we can test every single function in isolation.

If all the basic functions are correct, we can be (almost) sure that a bigger and more complex function composed from these building blocks is also correct!

Today you will learn four methods used to compose Option together:

  • alt: Provides an alternative Option in case the current one is None.
  • andThen: If the current Option contains a value (Some) return a new given Option.
  • flatMap: Extract the value inside the Option if it is present and return a new Option, otherwise return None.
  • getOrElse: Extract the value if present, or provided a fallback value if it is not present.

I highly encourage you to read the previous article in the series. Many of the basic concepts have been explained in the previous article, so you may have trouble understand this post if you do not read the previous one.


Shopping with Functional Programming and Option

The example of this article is all about shopping:

You want to go shopping. Your first option is going to the Shopping Center. Nonetheless, if the Shopping Center is closed, you will go to the Local Market, which is always open.

You want to buy exactly one Banana (🍌), one Apple (🍎), and one Pear (🍐). If any one of these fruits is missing, you will leave empty handed and not buy anything.

We will model these instructions using Functional Programming with the Option type!

Shopping Center, otherwise Local Market

Your first idea is to go to the Shopping Center. You define a function for doing this:

Option<Unit> goToShoppingCenter() => getRandomOption(unit);

getRandomOption(value)

This function returns the given value randomly wrapped in an Option: Some(value) half the times, and None() the other half.

The function returns an Option, since 50% of the times the Shopping Center is closed!

You also define an alternative function to go to the Local Market:

Option<Unit> goToLocalMarket() => some(unit);

This function always returns a Some, since the Local Market is always open!

Now you want to combine these two functions. You try to go to the Shopping Center. If it is closed, you will go to the Local Market instead:

goToShoppingCenter().alt(
  goToLocalMarket,
);

We use the alt function. If goToShoppingCenter is Some, then alt will just return this Some, If goToShoppingCenter is None instead, alt will return the result of calling goToLocalMarket.

And then, once we are in the market, let's buy

Regardless of which market we choose, we want to start buying some fruits!

We don't really care about the Unit that the two previous functions return. We are just going to ignore it and start buying:

goToShoppingCenter().alt(
  goToLocalMarket,
).andThen(() => /** Let's buy! */);

The method andThen throws away the result of the previous Option if it is a Some and just calls the given function. If the previous Option is None, then andThen will also return None.

Let's but banana AND apple AND pear, nothing otherwise!

Now you are inside the market and ready to buy. You want all the fruit on your shopping list. If any of the fruit is not available, you will just leave and not buy anything.

We define three functions that give us our fruits (only 50% of the time):

Option<String> buyBanana() => getRandomOption('🍌');
Option<String> buyApple() => getRandomOption('🍎');
Option<String> buyPear() => getRandomOption('🍐');

You are going to check the availability of all these three fruits one by one. If, at any step in the process, you don't find the fruit you were looking for, you will just leave all the other fruits taken since then and leave:

goToShoppingCenter()
    .alt(
      goToLocalMarket,
    )
    .andThen(
      () => buyBanana().flatMap(
        (banana) => buyApple().flatMap(
          (apple) => buyPear().flatMap(
            (pear) => Option.of('Shopping: $banana, $apple, $pear'),
          ),
        ),
      ),
    );

We use flatMap to chain these functions. flatMap will call the given function only when the Option is Some. If any of the Option in the chain is None, then the whole chain will return None!

Get what we bought, or else nothing

Finally, once you are back home you check what you bought. If you did not find your fruits, you will just notify your family. Otherwise you will show the result of your expedition:

// Combine all the instructions and go shopping! πŸ›’
String goShopping() => goToShoppingCenter()
    .alt(
      goToLocalMarket,
    )
    .andThen(
      () => buyBanana().flatMap(
        (banana) => buyApple().flatMap(
          (apple) => buyPear().flatMap(
            (pear) => Option.of('Shopping: $banana, $apple, $pear'),
          ),
        ),
      ),
    )
    .getOrElse(
      () => 'I did not find 🍌 or 🍎 or 🍐, so I did not buy anything πŸ€·β€β™‚οΈ',
    );

getOrElse returns the value inside the Option if the Option is Some, Otherwise, it returns the given value in the provided function.


We record the results of our visit to the market for 100 days, and this is the result:

Result of combining the Option together in a chain using Functional Programming

Sometimes you find all the fruits and you buy them, other times you just leave empty-handed.


Recap: What we learned in this article

  • How to use the methods alt, andThen, flatMap to chain functions returning Option
  • How to use getOrElse to extract the value from an Option
  • How to model a Functional Programming application using Option

You can find the complete example in the fpdart repository:


Do you like these short articles on Functional Programming? Let me know on Twitter at @SandroMaglione. Follow me for daily updates on Functional Programming, dart, Flutter, mobile, and web development. If you are interested in more tips and guides about these topics, subscribe to my newsletter here below πŸ‘‡