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

The "Task Practices" 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 goes over different Task monad examples and familiarizes the audience with the Task syntax, and characteristics.


Transcript from the "Task Practices" Lesson

>> It turns out what I've been talking about this whole time about how some of these are confusing, this one's pretty confusing. So don't feel bad if you weren't able to just run through these quick, it is probably my fault. But let's go through it, and hopefully we'll learn something, and improve these.

So right off the bat, the first one we wanna call to uppercase and title. The result of this, getPost returns us a task of a post. So if I wanna get the title of the post, I can map over it. Get to the post, and newpost.title. And I can choose to then map again on the title to uppercase it, uppercase, Or I could decide to do it in one go.

And that follows from that property we were talking about before. Two maps, a map followed by a map can be the composition of both functions. Composition inside one map, which is cool. So we can use that to decide whether to break this apart for a more of a separate.

I don't care about the post. If I decided I never wanted to post after that, and I wanted to contain it, so that it's gone from my memory, and I can focus on just the title. This might be the way to go. Or if I just wanna deal with it, one guy could do that, no big deal.

It may be a performance boost, maybe if you're doing this 100 million times.
>> It's failing me. I don't know if it's-
>> I had the same problem. I had to refresh my code pen before it actually ran it. And I was like, why is going on? I'm starting to sweat.

I was like, everybody's failing, and it's my fault. [LAUGH] all right, so then we go to comments for posts. And this is the one that I think is a little bit not as defined as it should have been. The idea is that you wanna pass the post, right?

So we map over it, we get a post, and we wanna pass that into getComments. So we'll get the comments with that post. Then we wanna assign the comments returned to the post, so that we have a t.comments, t being the post with a terrible name. All right, so [LAUGH] with a functional programmer name, very, very important.

So we go to this, use two spaces for tabs, and it's killing me. But if we weren't both in scope, remember, we can just nest it in enclosure. We'll just map over that to get comments. Now that we have both posts and comments, you can kind of see this nesting.

They've got two variables in play right now. And then we'll go ahead and say, well, it's just object, assign comments to the post. However, we've done a task, so we have a task of post. Then we get comments. Again, that's a task of comments. So then at the end of all this map, we end up with a task of a task of this post with comments.

So what we'll do is just change this map to a chain work. And that flattens this down and gives us our answer. And is not happy. So this could be made a little bit nicer to read. You could try to, I don't know, this is fine, fine, fine, fine.

But the point is that if we need multiple things, and this is where async await, if you wanted to make it work with any monad, it might come in handy if you have multiple variables. So elsewhere, nesting kind of tells you how deep your context is. So pick pick your poison.

All right, so there's that one. Let's go to last one, nice and easy. Wrap location href in a task to make it pure, mathematical. So let's go ahead and do that. We'll say task, and I, again, I think I messed up a little bit here in that. Some of the other things I've done actually defined task up here.

But this one brings it in from folktale, and folktale, which I haven't done all the way up until now, is new. So there's me setting you up for failure, and I apologize for that [LAUGH]. But it looks like this can never fail, right? If I try to get location href, it's gonna be there.

So I'm just gonna ignore the edge right here. But, if it were, maybe we could do it in a try catch, and we'll talk about that situation in a minute. We'll circle back on that one. But here we are. We just wrapped it in test, cool, nothing too fancy there.

We could also maybe wrap location in a task, and then call .href on it. But I have a suspicion that if you call .href, maybe something fancy is happening. If you set text content on a node, that is a side effect, but it doesn't look like it. It looks like you're just setting a property.

Sometimes you have to kind of know if it's a side effect or not. Yeah, so let's just go ahead and start right here. What we're gonna do, so this is fun. It has me wrap this thing in a task. And if I do task, the new task on this one, apologies, regress, and we just resolve this, and it passes, and things are good.

I wonder if I take away the new, if it still works? It's not happy. What are you doing wrong? Get href? Look, check this out, as well I was gonna show you. To get href, it could be a function, right? And then all of a sudden, it works, or it could just be a value.

I mean, this thing hasn't run. Same exact results, right? It has the function in the task. So you're saving yourself an object instance, in this case. But perhaps maybe if this was an already resolved task, then it would just continue to give you the same value. Maybe you want a new one, so you can do that.

I typically do this not to be on the safe side, to be honest, but that's kind of interesting. The other interesting thing here is we're about to talk about, if I wanted to do like a try catch in here, and if this blew up, call the reject. And I could do that manually, or I could use either as try catch.

But what I'd end up with is a task with an either with whatever, like null, or the actual value. And the task has the rejections side, and we actually don't call that. This would just be basically null, cuz this never gets called, because the try catch would be inside the thing over here.

These kind of nested effects is what we're gonna talk about a little bit, and then we'll build an app to just kind of use this stuff. As promised, I wanted to quickly touch on that of method before we go into nested effects. So if I have a task of 2, that just puts 2 in there, right?

And I can fork from there, I can map from here, right? I've got 2, and I can start doing 2 times 2, so on. And we'll fork that console.log, blah, blah, blah. Great, so that's cool. I can just pop a value in there. I don't have to use its specific constructor to get it to do that.

It ignores the error side, and just starts with success, cuz I'm just putting a value in there, and we're just gonna start mapping over it. If I started with reject, none of this would happen, and it would be weird. So for our intuition, of should pick the successful side.

And we kinda define this loosely, as the default minimal context. ID is just box, ID should have an of, and it doesn't have. It's not forked, okay, yeah. And extracts here. Yeah, it's not fold here, sorry about that. Either has that, right? We can fold it down into console.log.

Console.log, should have done this one first, and so on. So of in JavaScript is a interface to program to, in order to get your value inside a type. In fact, if we call list.of, fold on this, I love this [LAUGH] with a toJS. So I'm bringing in a mutable JS as of now.

And I'm bringing my extended form to kinda show some extra things. We're not gonna do exercises, I just want you to be aware of some of these extra APIs that you might need to know. You can do 99% of everything with what you know, as of right now.

But you're gonna run into some cases. And these cases typically are centered around nested, different types. So I wanna talk about them for a second, and then we'll build some stuff. But is everybody good with of? Just pop it into type, don't worry about its constructor, and it's an interface to program to, we call that appointed functor, a functor, the way to put a point in there.

And then a monad, just to just to finish up here is is if I chain things, I have to put this back in a list, right? Because I'm chaining. So we define a monad as a pointed functor with the chain. So a monad is not just chain, it also has this method, because we're dropping out of the type, and we need a way to put something back in a type.

If we don't have that in a nice clean interface like of, it breaks the whole interface. So those are the last kind of things there. I honestly probably won't be using of all that much, but it's good to know.

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