Understand the Maybe Data Type

    Andy Van SlaarsAndy Van Slaars

    In this lesson, we’ll get started with the Maybe type. We’ll look at the underlying Just and Nothing types and create a simple utility function to create a Maybe from a value. Then we’ll see how we can apply functions to values and skip invocation for values that might cause errors or unexpected results.



    Become a Member to view code

    You must be a Member to view code

    Access all courses and lessons, track your progress, gain confidence and expertise.

    Become a Member
    and unlock code for this lesson


    Instructor: 00:00 Here we have a utility file where we're exporting a few simple utility functions. The ink function accepts a number, returns a result of incrementing that value by one.

    00:09 We're pulling increment into our index.js file with require and currently we're just taking the input value of two, applying the increment function to it, and logging the result.

    00:18 As we can see from our output, this is working fine, and we're getting a result of three. If I were to change this to another number, like four, we'll see the result will be five. Eight will yield nine. Everything is working as expected.

    00:30 The problems start when we turn this into a string. Then, we start to see weird, unexpected results. Passing eight as a string here is going to yield 81 because that plus operator then becomes concatenation because it's operating on strings.

    00:45 If we change this to undefined, we're going to see that our result is not a number. To avoid these unexpected results, we need to make sure that we always call increment with a number.

    00:56 Let's do that in a simplistic way. Let's check type of input and see if that is equal to number. If it is, we'll call it increment, and if it's not, we'll just return zero here.

    01:12 Now, we'll see when we pass undefined in, our result is zero. This works, but it's not ideal.

    01:17 Our code is a little bit harder to read now. We don't want to have to do this every time every time we call a function that expects a number. We can avoid this by moving the type-checking code into the increment function, but that only works for code that we have control of.

    01:30 If this function came from some third-party module, that wouldn't really make the most sense. Let's pull the maybe data type into our project and see how we can use that to provide some safety for this function.

    01:41 In my terminal, I'm going to install the crocks library with MPMI-s crocks. With that installed, we come back into our code. I'm going to import crocks. I'll import const maybe. That's going to equal require crocks/maybe.

    02:08 Maybe is an object that's going to wrap our value. It's going to let us differentiate between values that we want to act on and values that we don't want to act on. This works because maybe is a union type, meaning it's made up of two underlying types and it can be one of those at a time.

    02:24 It's made up of either a just that holds a value, which we'll call X here, or a nothing. Just represents a value that we want to act on, and nothing will represent something that we don't want to act on.

    02:38 Let's take a look at this in action so we can get a better understanding of it. Let's replace our input. We're going to do that by calling maybe.just to construct a just with a value in it. We'll give that two.

    02:51 Then, I'm going to replace this result line using maybe. Input as an object, we're going to have some methods on this.

    03:00 One of those methods is map. Map is what's going to allow us to apply whatever value is in that just to a function. We can pass ink into map. We'll see that our result now is a just of three.

    03:13 What happened was we wrapped up our two in this maybe. Then, when we called map on it to apply to that function, the maybe unwrapped the value, got the two out, passed it into ink, which is expecting that number. Got back the result three, and wrapped it back up in the just for us.

    03:30 Now that we know this is working, let's change our code up a little bit. What I want to do is I want to extend the function that we're passing into map so that we can log out any time we call ink. I'm going to accept a number here. I'm going to pass that into ink. We'll still get our result back.

    03:46 Before that, I'm going to add a console.log and I'm going to point out that we're calling ink. Because console.log returns an undefined, we can or to get the call to our function. We'll still end up with our return value for ink, but we have a nice, neat way to log out that our function is being called.

    04:09 I'm going to save this. Then, in the terminal, I'm going to run this by pointing to my folder with note. We'll see that it's calling ink, and then we get our result.

    04:20 Now that we have this logging code in place, let's see what happens if we change our input. Instead of passing it a just of two, we pass it a nothing. The nothing constructor is going to get no value because it represents nothing. We'll see down here, our result is a nothing.

    04:35 If we save this file and then we run this in the terminal, we'll see that we're going to get our nothing back. We didn't get our console.log for calling ink because it actually skipped mapping over that function.

    04:47 If we have a just with our value, it's going to invoke that function that we passed to map. If we have a nothing, it's not going to invoke the function. This means all we have to do is properly wrap our value based on whether it's a valid argument for our function or not, and we'll be safe from unexpected results.

    05:06 Let's create a function. I'm going to call this save.num, and save.num is going to take in some value. Then, we're going to decide if we want it to be a just of that value or a nothing. We'll do this based on whether or not it's a number.

    05:23 I can take this out of our old result line. We'll check the type of val instead of input this time. If it's a number, we're going to construct a just wrapping our value. Otherwise, we'll return a nothing.

    05:42 Now, we can come down here. We can clean up this incomplete code in the comment, and then our input is going to be a call to save num, passing in our value.

    05:51 If we pass in a two, we'll see that our result is a just of three. If we pass in a five, we'll get a just of six. If we pass in undefined, we'll get nothing. If we pass in some string, we also get nothing.

    06:08 Empty array, object literal -- all of these things are going to skip over our function that expects a number and yield us a nothing. Using the maybe type, we've added an element of safety to a function without having to change that original function.