Check out a free preview of the full Hardcore Functional Programming in JavaScript, v2 course
The "Either 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 examples of using the Either type using the dot syntax, and explains that, when working with Either, it is not possible to flatten an array of another type.
Transcript from the "Either Practices" Lesson
[00:00:00]
>> Here's we're gonna try to do, we're gonna try to write street, again, with either. And what we'll notice is that there's an if else, and when you see an if else here, you can think, I might be able to do this with either, will it help me?
[00:00:14]
Well, it actually make my program safer or is an if else the right thing to do? One thing I should mention is ternary operators. If we did this return address, address.street otherwise, no street. That is way more functional than an if else. It's a single expression, there's no way for me to run a bunch of rando computations in the middle of that.
[00:00:44]
This is in line with our returning of value rather this over here with if else, I can do like saveToDb. There's just like a bunch of steps I run in here and it doesn't really flow. So, just you should add that, you don't have to use either whenever you see an if else, [LAUGH] ternary is just fine.
[00:01:08]
Okay, so let's go ahead and start the way we start by, why don't we just say we'll put it in a fromNullable. So this is a way to put it into neither will either get a right or left here. Or left with the address. And then, what we'll do is map over it to get the street.
[00:01:31]
And actually it turns out, Just get rid of this, not keeping with my best practice of leaving the old one on the screen, sorry about that. But we could map over it and get the street right here where we have the address, and then we fold it out.
[00:01:47]
And we say, if you don't have anything we'll just say, no street. And otherwise, we'll just give you the street. And, I could do this in one fell swoop by just folding it here or actually get rid of this, we get the address here. We go address.street. Either way's fine.
[00:02:10]
I tend to prefer the map, map, map, and then fold just returns just takes the value out. So you're not doing these kind of computations. You end up having to refactor. Like, no, I have to do something else, I have to push this out into a map. So, but either one's totally acceptable, except you're wrong if you did this one.
[00:02:27]
[LAUGH] No, I'm just kidding, there's that. Okay, what's happening there? I don't know. Cool, happiness. Happiness is a green passing bar if you do TDD which I do less of these days, the Internet's hard, y'all. Did the null check, nice and functional, linear control flow null checks. Also, I should mention like all this can be written in point free, like we learned in the first half of the day.
[00:02:59]
We can do some of that when we build the app we can choose our own adventure. But yeah, this is all perfectly functional in either way. Since refactor stream, again just to reiterate, we're doing .syntax because I've seen the second half of the class which I feel is much more important.
[00:03:19]
Start to unravel and fall apart if we try to stay point free all day cuz a lot of people just learn that and they're just trying to it's just too much. So we're reverting back. I also tend to like .syntax in JavaScript in particular. Okay, this one has two null checks, it's the same thing as above, right?
[00:03:39]
We do a nullable here. We're gonna map the street over that, but that could be null and then we're gonna get the streets name. So, let's do that. I can just copy this part, right? Nice and easy. I will keep the old one around streetName is that what it's called.
[00:04:01]
Cool, and it takes a user. And so almost there, we get the street. And we could map with the street, get the street.name. And, the problem here is that, well, first of all, what do I do wrong? I got name of null, there we go. So I need to do another fromNullable around the street, Which, again, gives me a either a right of the street, the thing with the name.
[00:04:42]
Or right of a left of nothing or a left of nothing, so on. But at the end of the day, just chain, green. Questions on that one? Hear you're doing it, your mon outing.
>> if it wasn't like an objective null, is there like you would you wrap map it or do some other word of four point attic transformation of insurance like an object or something or?
[00:05:12]
>> For which object [CROSSTALK]?
>> User, was undefined?
>> Of user, boom, yeah, let's just do that. So we don't know if users here. Let's do that and then we'll just chain. We definitely have a user here cuz that's how either works. Boom, that's exactly right. And this should all pass.
[00:05:34]
And we just started by saying this may or may not be there. So let's just wrap it in a null check and we'll just change through these. And if I'm like definitively sure we'll never ever hit an all in the street if we get here I can map, that's fine.
[00:05:49]
Of course, we will help it hit an a null cuz I built it that way. [LAUGH] But yeah, Cobain's good question.
>> What's up?
>> Some of that implementation would also be supposed to functionality decision where do we need to tell the user that the user object is failed?
[00:06:04]
Or would have been more useful to report the deeper structure or the higher structure, is that correct?
>> That's a good call. This kind of propagates the error like there's an error somewhere. Here you go. [LAUGH] And as we change, what you can see is we're swallowing, we're recovering the error here.
[00:06:23]
Particularly like fromNullable is like I'm just gonna return a left of just nothing. And, if you want to capture that this one particular thing was null, I think there's ways. But actually, when we can do it is this. [LAUGH] And then all of a sudden, I have a right of a right of the name.
[00:06:48]
And it's kind of neat to see that like the stack is like, at what point that things go wrong? I could also do something like this. I could say user if we have it, We can do something like this, user left, no user, right? Cool, or I say user, sorry.
[00:07:17]
And then we can map over that, right? And then whatever happens, we'll get pushed down to that fold. So, there's different kinds of approaches. But I tend to find that most of the time if something goes wrong, you just wanna push this out. And in fact, you usually wanna do that.
[00:07:37]
So the color of street name gets to decide how to handle that when they had a problem. These test cases are a little bit misrepresentative of that situation where like, null street name is a beautiful function that takes a user and returns us an either of null or a name, a street name.
[00:07:58]
And, I can see right here that this thing is gonna give me on or the other and when I call it I know how to handle one or the other. The unfortunate thing about fromNullable is the way we defined it is we didn't give it away to say, what's wrong, like an error message here.
[00:08:20]
Let me just put that right here if we wanted, if I could type, [LAUGH] but we can't, I can't, so we won't. But it's, yeah, it's kind of a way to be able to embed an error message in your left. And for those of you who know the maybe monad, I've just given up, I just don't use it.
[00:08:38]
I only use either, because you can provide an error message. With maybe, it's the exact same type of can't provide an error message or just not there, it's there. And so I tend to use either with the exact same results and as we'll see a little bit later today, the nesting of different types within each other, you can't flatten.
[00:09:01]
If I haven't either have a maybe I can't flatten that. I have to have an either have an either or maybe have a maybe, I can't flatten an array of another type, right? So, that situation that happens is a big deal. It's a lot of what we're dealing with when we're trying to write functions like this and we're only gonna touch on this at the end, but it helps to normalize your types.
[00:09:22]
I'm just gonna use either everywhere or task or this. So you're not having to deal with situations where you have a maybe of an either of a tasks. All right, parseDbUrl. This one's fun. What we're gonna do is parse the configuration then match on that. And, it looks like, This will blow up if it can't parse.
[00:09:46]
I'm not sure if this is gonna blow up. So I don't know if I need to run it in a second. Try catch, but let's just see what happens. All right, let's copy and paste. Okay, so we got parseDbUrl, and I was gonna rename, it'd like two lines, right, super easy, const parseDbUrl, it's config.
[00:10:11]
We're just gonna tryCatch, and we're gonna parse it, cuz this could blow up. And then we're gonna map. We can do something fun here in a second, let's change it up a little bit. And then finally, we're gonna fold out the last value, which again, in this case, just whatever, identity, I think that's right.
[00:10:37]
Yeah, missing argument to this, there it is, cool. So, we got, Null, expects to null is the thing that is the return on?
>> Yeah.
>> Cool, all right, great. So and that's capturing this, so you got an error, but I threw it away in return null instead of the actual error, which probably should have done that.
[00:11:03]
Anyway, that's fine. One thing we could do, but yeah, we could actually log the error here like cuz tryCatch tells you the error. I mean, this is like the actual error that passed through. And then also, another thing that's interesting to me is that here, we could start by saying, well, you know what I can do, I'm gonna put config in right just like we did before with the box.
[00:11:25]
We're just gonna start with something. And then once we started with it, we can start to chain, right? Could do that. And we should get the same results. So, just like we put config in a box with chain over it, just like we put other things in a box to start it, kind of kick it off.
[00:11:44]
Now, why did I choose right, instead of left.
>> Reduction.
>> [LAUGH] Fair enough. None of this would have happened, right? It would have just ignored it all went right to the null. And, the other thing that's interesting is there's this concept that we have of a pointed functor.
[00:12:09]
A functor that you could put something in through an interface that I don't have to know about right is the right answer here, box is the start point there. And we'll look at that in a minute. But the correct way to handle this would be something like that.
[00:12:25]
It has a .of method to say like put it in the type and then, just start running through it. So that allows you a generic interface to insert stuff into a type. We use right here because I wanna show you that once we have a few more monads that really kind of explain what's going on there, yeah?
[00:12:43]
>> This dot of method is a JavaScript isn't it, is that correct?
>> It is, you've heard that maybe college.
>> I know other languages can instantiate that way and that's why I'm asking.
>> That's exactly right. There's sustaining things unit or pure.
>> Okay. So, last one, see if we can get through this without any errors, fingers crossed.
[00:13:08]
All right, so we're gonna use either in the functions above, refactor startup. Okay, so we're gonna parse the DbUrl, I guess this one means that we have this one finished, right? And, let's see here, start by calling parseDbUrl. It says if parsed, okay, so it actually showed up because this one returns a null, if it doesn't, right?
[00:13:40]
So we'll do it fromNullable. Then, grab this stuff. Let's be fancy destructuring anyone? [LAUGH] For the win. So, If we've got parsed we'll just destructure it right there and then we'll return this, we'll transform it into that. Otherwise we'll do that, okay, and we'll fold on this error.
[00:14:15]
Otherwise we'll just get that string out of there. And everybody's passing, cool. But it did have one thing to mention here. So parseDbUrl returned. If, again, if folded it out right there, because they made you from this test, but in a much more realistic scenario, you wouldn't want to do that.
[00:14:37]
Let's like just say, hey, parseDbUrl tells us it's either gonna succeed or failure. And then I have a color over here, right here of that. I don't have to call fromNullable, like if succeeded, just keep going. Keep rolling, baby. [LAUGH] So like you typically don't wanna remove it from its context if you wanna continue composing, it's part of the whole point.
[00:15:02]
If I have something that tends to be a problem for when you get started is that like you put something in either you're working with it, you're like, no, I wanna get it out. But what if it's not there? I mean, there's like it might not be there.
[00:15:17]
[LAUGH] And so if you just continue the rest of your program as though it's there, leaving it in the either and mapping over it, everything will work out great. But if you try to take it out there you have to like unfold it and handle it and deal with that error there.
[00:15:29]
And then, event never really find yourself like trying to unwrap and put stuff back in and take it out and put it back in. It's nice to leave it as the return type is what I'm saying. Unless you're returning like an MPM package and people have to map over it and they're like [NOISE] I don't like either, I don't understand.
[00:15:46]
[LAUGH] All right
Learn Straight from the Experts Who Shape the Modern Web
- In-depth Courses
- Industry Leading Experts
- Learning Paths
- Live Interactive Workshops