Transcript from the "Either Monad" Lesson
>> We're gonna talk about a type called either. And this is going to be functor in a monad, meaning it has a map and a chain method. And it's gonna have a fold method which we define, we call that foldable. So it's a foldable functor monad, all the good stuff.
[00:00:16] I'm finding that teaching the data types like box, we'll learn either, we'll learn kind of IO or task. You start to see the same APIs applied to different types. Rather than introducing, there's this thing called map and it works on anything. It's like, here's a few concrete examples of map, and now try to see the commonalities.
[00:00:34] Same thing with chain, same thing with fold. So look for the commonalities here, and see how it's the same API across different types, providing different functionality. So in this case, we're gonna find a color, pass in a name, and we're just gonna grab the hex value out. And our value's red, and if I misspell it, I get undefined, whatever.
[00:01:01] What if I wanna toUpperCase, Boom, all right, that's cool. But then if I misspell it, uh-oh, null.toUpperCase or undefined.toUpperCase. So how do we deal with this null issue? So let's go in and use a box. And for this box, I'm gonna go ahead and copy the boilerplate from here.
[00:01:36] So, actually, get rid of that, that, cool, we got chain, map, fold, everybody's good. But here we have two types, a right and a left. Don't worry too much about the implementations themselves. But I want you to see that the map here on the right runs the function, keeps in right.
[00:02:01] It's exactly what we did with box, right almost exactly is box. I think it is box, no, fold is different. Left does not actually run any of the functions. You're like, here, left, please run this function for me, and it's like, nope [LAUGH]. So how is that useful?
[00:02:20] So you can think of these as two subclasses of a superclass we call either. And so we could define this multiple different ways. I'm just making two different types and then using the gap to say, well they both have the same superclass, they're part of an enum supertype called either.
[00:02:41] But let's go ahead and use them. So we're here in findColor, and what I'm gonna do is, I'm gonna refactor this a little bit. Let's go ahead and say, that const found is that. And if we have a found, we'll return a right of it. Otherwise, we'll return a left, not found, great, how about dunno?
[00:03:09] [LAUGH] All right, so what's gonna happen here, let's get rid of the, toUpperCase, is we get back a right of the value, right? It went through and it found it. If I don't find it, I get a left of dunno. So I'm choosing within the function to push to the color that we're gonna find it or not.
[00:03:32] So I want this hex value, to get at it, I either have to fold it out or, let's go ahead and first map x.toUpperCase. And there it is, we've uppercased it, and if I misspell it, guess what,left still doesn't care. It's like, yeah, whatever, [LAUGH] I'll write missing instead of dunno.
[00:04:00] So you're trying to find the color, and you didn't find the color, but this didn't blow up, right, we got the error message at the end. So the other key difference is, again, give myself some space here, kinda write it in function form. The other key difference here is that, to get it out, now that I have two different types, a left and a right, we have a fold that takes f and a g.
[00:04:28] f handles the left case, it's on the left side, g handles the right case. So we are gonna run the function and get it out of the type, if you're a left, it runs the first one, if you're a right, it runs the second one. So let's see this in action, down here in the fold, I'll say, on the left case, I get missing, so I'll be like, no color.
[00:04:55] And on the right case, I actually get my value, which is the color, so just return it. And it's got no color, so I can actually handle my error. If I pass in the right color, if I could type, boom. So what we've done is, findColor refuses to let us deal with the undefined case.
[00:05:16] It says, hey, I know that you're gonna give me a color that is not gonna be found one day in the future. And I'm gonna force you to map over the box I've provided, and it's the happy case. Let's say if I say map, and we'll do x and x, it's got the first part of it, or actually slice out that hex value, for instance.
[00:05:40] So there we go, right, and it's gonna do all these things, it's just the happy path. And if if it doesn't find it in the first place, it just skips all of it and goes right down to the error handler. So two things to notice here is, it's exactly like box.
[00:05:58] But in the right case, we're actually continuing the composition. And in the left case, we just cut it off right there and return that value. None of this ever runs, and we're bubbling up the error to the color. The calling function receives the error handling ability. And if I didn't wanna do that here, I just did that, then whoever calls res has to deal with the error if I wanna fold it out here.
[00:06:27] So we've done this inversion of control, where the caller has always had to do these null checks and deal with these functions. I hope I called it right, boom, right, one day you get bad data. Here, now the caller has to actually manage and maintain and deal with it.
[00:06:43] So we've inverted that, it's a safer operation. So let's put that fold back on. So this is either, and now you can start to see why map is cool, right? You're saying, please apply this function for me, and this one just doesn't. And so we've got this inversion of control.
[00:07:02] We've got this right, left, we've got purity. We didn't have to throw an error, right, we returned a value that represented an error. And this doesn't just have to be error handling, we've just got two values. Just by convention, since left doesn't actually do anything, it just cuts off the computation, it tends to be used as an error kind of value.
[00:07:23] But this is the canonical some type, I have two things, it's one or the other. I can return you a right or a left here, and I can just pattern match down here and do two different things, I can branch my code. It's effectively an if-else, but inverted, which is pretty kick-ass.