Check out a free preview of the full Hardcore Functional Programming in JavaScript, v2 course

The "Task Monad" Lesson is part of the full, Hardcore Functional Programming in JavaScript, v2 course featured in this preview video. Here's what you'd learn in this lesson:

Brian explains that the Task monad is the functional equivalent of promise. Similarly to promise, Task takes resolve and reject functions, but in reversed order. A Task monad only starts running once it reaches the fork method, and this way avoids race conditions.


Transcript from the "Task Monad" Lesson

>> So Task is Promise, it's exactly Promise, it's just lazy. So that whole kicking the computation down to the callers [LAUGH], side of the court. So, one thing I think is really interesting. Before we go into this, we have Box, right? And we could say, well, you take your X.

And then, what we're gonna do is, we're gonna map over the, you give me a function, I'm gonna directly run this on that. A different way to make Box would be to take a function. And then if I map a different function over it, I could just do function composition.

So now Box is holding a function. And, mapping is literally function composition. We could do this, we could say, Box take something that returns, let's just start with the value 2. And then we'll map over that, and we'll do, two + 1. And let's go ahed and bring in compose from Ramda.

And, we don't have a way to run it yet, but folding, what would folding be in this situation? How would you get this out of the Box?
>> Do you just run the function?
>> Yeah, f [LAUGH]. And there you go. Interestingly, this is starting from the basis of the reader Monad, you're making a function into a functor, and mapping this composition.

And it gets into these category theory constructs, where you can make either in the lazy, and back and forth. But, my point in showing this is that. Knowing that I can always make a functor lazy with the function, and mapping its composition is a very useful thing to know.

Because then I can say, lists are eager, if I have an array, I map, it's gonna run through it. But I can make an event stream that's like a list but it's lazy, and it doesn't run through it. Or I can make a lazy list. And mapping is just composition.

And knowing that upfront really helps you build these types. And same thing with. So this is how we're gonna be able to do async without dealing with it directly. So let's do that. So we have Task. And Task has an of method that I kind of alluded to earlier, I can just throw something in it.

Task.of2, map over that, do two + 1. And, all right. So, what we have here is this thing, a Task holding a 2. Let me do a more conventional constructor. Task takes a reject and resolve function, just like a Promise, but they're flipped. Notice they're flipped. Why would they be flipped?

Anybody have any ideas?
>> To go with left and right?
>> Sort of that, actually makes a lot of sense. I would agree with that.
>> [CROSSTALK] first.
>> Yeah, promises are typically, you'll see like that, and then they never catch the error [LAUGH]. Like, well, whatever, I don't care.

You kind of push this first, they're like, no, you have to actively ignore that callback. That's, I like that. So, we can do res(2), and that's exactly how this is defined. It's just like, put this in there. Map over that, (two + 1). All right. So we'll call this T2, or T1.

And, whoops. T1.fork. All right. So this is the big difference. What we're gonna do is say, this, hang on [LAUGH]. What did I do here? [SOUND] Res(2), there we go. Pardon me on that one. Okay, so we can map, adding something to it, and we could put whatever, map, what is this, three?

Three * 2. All right, so, this won't run, this won't do anything. That's the difference between this and a Promise, is, this just sits there, it's a computation. And, when it called fork, console.error, console.log. I get six. So, this is gonna call the, it's like fold, but we call it fork, because it's actually gonna go run stuff, and it's gonna fork the computation, it's gonna be this big thing.

In addition, we do have a way to fold tasks separately, but. I think of it as taking it out it sounds like folded, it works like folds, it actually runs the function. And so, some of the benefits here. First of all, why would you wanna make promises lazy?

What we do here is, we have a whole app working with lazy constructions, nothing actually happening. That allows us to put these in data structures, basically combine them, fold them together, change types around, without ever running anything. And they know what they're holding, this thing knows it's holding six.

Just like a Promise knows what it's holding, and, or an error. And, it allows us to continue to compose and combine, and do all these great things without actually running it. And then, outside of our application, we've got the caller, where I'm like. Up here is my beautiful clean, perfect mathematical app, and down there is where all the stuff actually happens.

We're able to run that. So we could do some really, really interesting things with laziness, but I wanted to kind of make the case for using Task rather than Promise, because it really does pay off. So, I don't know if I did a great [LAUGH] job yet, but, we'll lazy it a little bit more.

So, we have Task exercises. I think they're the last exercises of the day. And then we'll try to build an app for the rest of the day after that. But I wanted to do one more example here of Task. And iIt's almost exactly a Promise. So, it shouldn't be too hard if you already know Promise.

But the one thing is, this isn't just then and then, and then, you have to know if you're gonna return another Task.of two, one, whatever. You see how that works. It's not just then and then it's, know if you're gonna return it as a Task or not.

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