Understand the Maybe Data Type

Andy Van Slaars
InstructorAndy Van Slaars

Share this video with your friends

Send Tweet
Published 4 years ago
Updated 3 years ago

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.

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.

Tre' Codez
Tre' Codez
~ 3 years ago

Loving it!

Tre' Codez
Tre' Codez
~ 3 years ago

I wonder how you've made vs code show your return values! Rather cool

Also, what theme is that?

Tulio Miranda
Tulio Miranda
~ 3 years ago

@Wayne, I've just searched for that (couldn't continue with the class knowing that there was something as awesome as that to be discovered). I found the QuokkaJs product ( made by the same team that built WallabyJs )

So, there you go!

Andy Van Slaars
Andy Van Slaarsinstructor
~ 3 years ago

Yup, it is Quokka from the Wallaby team.

The theme in the videos is this one: https://github.com/orefalo/bcmarinacci.theme-material-operator-1.3.0

Platon
Platon
~ 3 years ago

Hi, how do I get "Just" + return value or "Nothing" printed in the console instead of an unwrapped Maybe object (check the console output to this lesson, it's some object of type "crocks/Maybe@3")?

Invoking option(0) on a Just returns "Foo" as expected.

Andy Van Slaars
Andy Van Slaarsinstructor
~ 3 years ago

Hi, how do I get "Just" + return value or "Nothing" printed in the console instead of an unwrapped Maybe object (check the console output to this lesson, it's some object of type "crocks/Maybe@3")?

You can call it with the inspect method like this: console.log(result.inspect())

tsvika
tsvika
~ 2 years ago

Thanks Andy, There's a hype around ADT these days and I'm trying to understand it. As for Maybe shouldn't Typescript or Reason resolve these kind of issues? what's the added value?