Maybe | Practical Functional Programming

Sandro Maglione

Sandro Maglione

Functional programming

Why functional programming? This guide will introduce you to real practical functional programming. It will be a highly practical explanation of functional programming, on why functional programming matters, and how to use it in your day-to-day coding.

Functional programming is not just a fad. My goal is to show you what you were missing without functional programming and why functional programming will make your code unbreakable (no matter what programming language you are using).


What is the problem with your code

Many of the bugs in your application are caused by your code lying to you. That's right.

Code is made of functions. Functions are supposed to return a value that you, the programmer, specify (at least in a typed language).

You trust your function; if you say that a function will return a double, you assume that a double shall be. What if is not though?

Let us see a simple example.

/// Returns the result of the division between `a` and `b`
double divide(int a, int b) {
    return a / b;
}

It cannot be easier than that! Writing code is easy. Writing code that works and scales is another matter. So, what is the problem here?

What if b is 0? The code breaks.

You can already see the problem. My function is telling me: "I shall return you a double". But then: "Erm…or I shall break your code…".

Two cases. One of which will never be found without testing or until a user finds out.

Let's fix this!

/// Returns the result of the division between `a` and `b`
double divide(int a, int b) {
    if (b == 0) {
        return 0;
    }
 
    return a / b;
}

Is this a clever solution? Does it solve the problem? Not at all.

The function does indeed return a double, but it is not what I expect.

I want the result of the division of a and b. In some cases the function does not return the division, but just 0. My assumption is broken.

If my intention is to display the value on a chart, the user will see 0! Not generally what we would expect I would say.

Furthermore, what if a is null? Another bug (that we will never find by ourselves).

Do you see where we are going?

Functional Programming "Maybe" to the rescue

The main problem is the defined types of the code. int and double.

It is not exactly int and double:

  • int can be an integer or null
  • double can be the result of the division or 0 or even an error.

Enter the world of functional programming. In functional programming the functions tell you the truth!

/// Returns MAYBE the result of the division between `a` and `b`
Maybe<double> divide(Maybe<int> a, Maybe<int> b);

Now you can read it much better:

The function is given maybe an int a and maybe an int b. It will return maybe a double

Maybe wraps your types to give them their correct names.

Now you are required to deal with all possible cases. Required.

In fact, you cannot just divide two Maybe. The / operator is not defined between two Maybe.

Instead, you must verify that both Maybe contain a valid value (not null), and then you can use them to return double.

Maybe a double, or maybe nothing.

/// Returns MAYBE the result of the division between `a` and `b`
Maybe<double> divide(Maybe<int> a, Maybe<int> b) {
    return a.when(
        nothing: () {
            // Value of `a` is not valid!
            return nothing();
        },
        just: (int validValueOfA) {
            return b.when(
                nothing: () {
                    // Value of `b` is not valid!
                    return nothing();
                },
                just: (int validValueOfB) {
                    if (validValueOfB == 0) {
                        // Division by 0 invalid!
                        return nothing();
                    }
 
                    // All valid, return JUST the correct result
                    return just(validValueOfA / validValueOfB);
                }
            );
        }
    );
}

The easiest of the functions, divide two numbers, just became a huge list of instructions.

Yes, exactly. But now it is a function that works. We can be (pretty) sure that this function is unbreakable.

What is functional programming all about

We just saw a basic example of functional programming. It is not difficult. An this is only the tip of the iceberg.

At its core the answer to why functional programming is very simple: because it ensures that your code works.

The purpose of Maybe is to convert your runtime exceptions in compile-time errors. It blocks you from even running the code until you take care of all possible sources of problems.

Humans need help to deal with complexity. Types and functional programming are tools that guide you in your path to production.

👋・Interested in learning more, every week?

Every week I build a new open source project, with a new language or library, and teach you how I did it, what I learned, and how you can do the same. Join me and other 700+ readers.