Check out a free preview of the full Functional-Light JavaScript, v3 course

The "Maybe Monad" Lesson is part of the full, Functional-Light JavaScript, v3 course featured in this preview video. Here's what you'd learn in this lesson:

Kyle discusses the Maybe monad by walking through code that uses chaining and explains how monads can be useful in performing common programming tasks functionally.


Transcript from the "Maybe Monad" Lesson

>> Kyle Simpson: Now, I wanna show you one specific way that people use monads. This is probably the most common of the illustrations out there for the usage of monads. To be honest with you, it's not actually the most compelling of the monads. But it's certainly the most common of them.

And it's called the maybe monad. So let's look at this object called someobj. It has some properties in it. And I've just, to save space on the slides, I put it all on one line. But you can see there in the comments that we can access the value by saying someobj.something.else.entirely and we would get out that value 42.

Which works great on this particular object. But what if one of those properties for whatever reason was null or undefined? Well, now we're going to get an exception, because we're accessing a property that's undefined. So if you've ever had the problem where you thought that you could access some deeply nested property in an object, and then you sometimes got runtime exceptions, you know exactly the use case I'm talking about.

Which is that you'd like to have some sort of safe way of addressing a nested property, but not throwing exceptions if it's missing. And there are countless numbers of framework and library utilities out there that pull out properties from a nested path and then give you undefined if something's missing or whatever.

But this is the canonical example for illustrating the maybe monad, okay? So we're gonna take that same way of accessing a property and we're gonna do it with a monad in a safe way, meaning that it won't throw an exception if one of those property levels had been missing.

Here's how we're gonna do it. We're gonna first define another monad, this one is even less interesting than the Just monad. It's called the Nothing monad. And you'll notice that Nothing just has map, chain, and ap methods that just make another Nothing. They don't do anything but make more Nothing's.

It's sort of the black hole of behavior. Because once you get a Nothing monad, Nothing else is ever going to come of that. Whether you call .map, .chain, or .ap on it, you're just going to keep getting Nothing monads. No behavior is ever going to occur. You're never going to execute any mapper functions, you're never gonna execute any chain functions, you're never gonna execute another monad's .map.

None of that's ever gonna happen. Nothing just becomes this black hole of nothingness. And that sounds existential, but it's actually really useful, because it's sort of the monadic way of representing no-op. I don't want anything to occur in the case where, in this case, a property was missing, okay?

So what we're gonna do is take Just, which we defined a couple slides ago, and Nothing. And we're gonna pair them together in a very specific way to make this other kind of a monad called the Maybe monad. So notice what Maybe is doing, line eight, I'm putting Just and Nothing together into an object.

And then I defined one other helper method, which I don't even technically need, but it's nice to have. It's a helper method called of. So you can say Maybe.of, Maybe.of is the same thing is calling Just, okay? Now I've defined another utility called fromNullable. And that sounds a little bit like a strange thing.

It's because a functional programmer named this, okay? I didn't name it fromNullable. But this is what functional programmers would call those particular kind of thing. And notice what frontNullable does, it's sort of an interesting idea. It takes a value and if that value is null, or in this case undefined, since I used the double equals operator.

If it's null or undefined, it just vends a Nothing. Otherwise it vends a Just with that value wrapped around it. So it takes in a value and it decides which of those two monads should I create? Should I create a Nothing monad out of that value, or should I create a Just monad out of that value.

It's lifting it if you will. I would have called it lift, they like to call it fromNullable, okay? It's debatable. I've been having some debates recently. It's debatable whether fromNullable is part of Maybe or it's just like a helper alongside of Maybe. Depending on your perspective, it's part of the monad or it's not part of the monad.

But it's certainly critical behavior to decide which one of those two monads do we want. Given any particular value that we're holding onto, should that become a Just monad or should it become a Nothing monad? So with that fromNullable, what we can do is define, in this case, another helper.

This is a functional programming helper called prop. This is one you'll find on all your functional libraries. Mine is a little bit special here. But this prop utility is curried. You'll notice that it's curried to take two inputs. It takes a property name and it takes an object and it extracts that property from the object.

I've made prop also have the fromNullable around it. So I really maybe should have called this like monad prop or something. Cuz it's not the general prop. It's this very monadic specific prop. So if I were to literally just call prop on some random object somewhere and tell it, get me x y z property off this object.

What am I gonna get back? I'm either going to get back a Nothing monad or I'm gonna get a Just monad that is holding the value that it found. That's what prop does, okay? So armed with this prop utility, we can now make a safe property chaining access off of our some object.

Because this is a monadic, you can probably guess, we need to turn some obj, we need to wrap it in a monad. And then we're gonna start calling with prop, we're gonna start calling to try to access the subproperties. So this is what that looks like. We say Maybe.of to vend a just from our someObj.

We also could've done fromNullable here, but it seems better to me to just be very explicit about it. We know it's a real good value, we want a just for it. So let's go ahead and do Maybe.of for someObJ, and then .chain. And notice what .chain is doing.

Prop of something makes this a function, doesn't it? Because remember, prop expects two inputs. So prop of something is exactly like earlier, when we were doing, in the course, when we were doing .map, and we said, like, add of 1, we did the currying of a binary function to make it a unary function.

Here we're doing a curry of the binary prop function, giving it one of its values. And .chain is being called with that result unary function. So Maybe.of of someObj, makes a Just around someObj. And then it calls .chain on it. And remember from a few sides ago, .chain is just gonna simply execute the function with the value that's in the monad.

So we've got our object being pushed into that unary waiting function. And it's gonna try to access the something property on that object. And it's either going to find it, in which case we're going to get a Just monad back, or it's not going to find it, in which case we're going to get a Nothing monad back.

But regardless of which one of those two comes back, we call .chain on line 21. We can call .chain because we know the previous .chain gave us one of those two monads. As long as it's behaving by the monadic laws, we know we can keep chaining. Just like with promises, we can keep doing .then, .then, .then, we can keep doing .chain, .chain, .chain, because we know we're always going to have a monad.

If it returned us a nothing monad, then what would the .chain on line 21 do?
>> Kyle Simpson: Just make another Nothing monad and another Nothing and just keep going and keep going and be a big old no-op, it's a big black hole of nothingness. But if it gave us a Just monad, then what would it do?

It would take the function that's waiting, prop of else, that's waiting on line 21, and call it with that object. And it'd either give us a Nothing or a Just. And then the same thing happens again on line 22, we either get a Nothing or a Just. If in all of those cases, we kept getting a Just back, because we found the property.

On the very last line you see my little cheat here to look inside of that monad that we got back. And you see that we would have a monad Just wrapped around the value 42. If at any point along the way, we got a nothing, it essentially short circuits the rest of the chain to be a no-op.

>> Kyle Simpson: So using the monadic laws and using this formulation of a maybe monad gives us a functional way, a functional consistent way, of dealing with this optional chaining idea. Certainly not the only way to do it. But if you're asking for or looking for motivations for how do I do common programming tasks, but do them the functional way, this is what we're talking about.

This is, we're moving out of the base of functional programming and just starting to glimpse into more meatier stuff, okay? This is certainly not a complete look at all that there is to know about a monad. But again, my goal is just so that you can understand a monad, not be afraid of it, and perhaps if you see a monad in an application, be able to understand what it's doing.

There are many kinds of monads. We've seen a few of them, the Just, the Nothing, the Maybe. There are Either monads, there's the IO monad, and dozens of other sorts of monads. We've only looked at a few of the basic principles. But armed with those, you should be able to begin studying other kinds of monads and broadening your perspective on where monads can fit into your program.

At this point, you probably have the exact same question that I've been having for months and months while studying this topic. Which is, should I really use these? Like, yeah, I get it. It's kinda like clever and cool and interesting, but should I really use them? And my answer, maybe, maybe you should use them.

But at least don't be scared of them. At least be able to see them and recognize them. And maybe understand what they're doing in a program. Because you might see somebody else use a monad somewhere. And it shouldn't be that your eyes glaze over and you're like, well, I got nothing to contribute to this code.

The spirit of us learning these things, of going on this journey, is that we embrace stuff that feels uncomfortable. We embrace stuff that feels weird and out there and beyond what we can find. And if we keep embracing it, eventually it becomes something useful. Someday, each of you on this journey, if you keep going, is gonna have that aha moment where a monad is exactly the right solution to something that you're trying to do at that moment.

And I'm somewhere in that journey of getting to the point where I can eat, sleep, and breathe this sort of stuff. I'm not there, yet. But I can at least articulate some of the benefits, the reasons why you might go about that extra effort.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now