Transcript from the "Creating the Identity Functor" Lesson
>> When we talk about dot chaining, we have composition, and we have this dot syntax. It'd be really great to dot chain this whole thing, you're gonna go in and you're like Brian's only a dot chain, I'm gonna dot chain everything. I'm gonna compose everything, either one, it's gonna make a simplier to maintain and read app, even though it's a little harder to do up front, it pays dividends down the road.
[00:00:23] And now you come in here and you're like, I'm gonna do it, and you're like how do I chain parse in on trims? How do I chain plus? I have this other, I can't chain any like, what's going on? What if I have like, what do we do this, right, like new number, that's no fun.
[00:00:41] This isn't gonna work, cause I do this all the time. [LAUGH]. Let's take away the new, why not. All right, so [LAUGH], the point here is, things aren't so dot chainable out of the box, pun intended. We're gonna define what we call box. This is gonna be the identity functor, formally, we're going to call it box right now to get an intuition.
[00:01:11] That analogy eventually starts to break down. But we're gonna start with it cuz it really, really helps explain what's going on here. So our mission for the next 10 minutes, if we choose to accept it, is to dot chain this. All right. In a nice linear control flow.
[00:01:31] I should say, you might be able to get away with composition with a bunch of helper functions here, if you wrapped everything in a helper function, but that's, we're gonna, let's call that cheating, for now. [LAUGH] All right, so we're gonna find box. And you can do this with a class, but I'm gonna do it right here, it's just a little like factory function, returns an object.
[00:01:53] Box is gonna have a couple of methods. It's going to have map. We're just gonna start with map. Now map has the same, don't worry so much about the implementation. But think about how you're gonna use this. So let me just go ahead and explain what's happening with map here.
[00:02:17] So if I, it looks recursive, but it's not, I'm just putting it back in a box. Run the function on the x, but keep it in the box. So I can continue to chain, if you will. So if I say result is a dot map to upper case.
[00:02:39] Wow, look at all the Czars, upper case. You know, it was in the box of an array. Got the A here, right? Uppercased it, stays within the box. What's in the box, so [LAUGH] means anyone. So then we get our X here again and let's go ahead and.
[00:03:06] You know what, I'm just gonna give myself some room here because this is starting to get cramped, here we go. And we'll call it result on there. Alright, so, once we're in this map here, what else can we do to it? Let's do this from char code, why not?
[00:03:25] Cool. So, what you're seeing here is already the start of what's happening. We're able to combine functions in a composition pipeline by putting it in this array, and mapping over that array, right? Problem is, this gonna happen for all the values in the array. And so, what we're gonna do is define our own kind of array-like thing.
[00:03:55] We'll call it box. Now box, we'll go ahead and, I don't know if I can skip both on the screen at the same time [LAUGH]. Let's move it down. Cool, we get a box out. This isn't very helpful. I wonder if this still works. We do box, and we put an X in there, the delegate.
[00:04:26] Yeah, cool, I mean, I guess [LAUGH], but the point is here, that we haven't left the box, so we can continue to map, we get another x and we can do like x, I don't know, dot first, I don't know if that actually works. [LAUGH] But let's go ahead and use this to define this function in terms of box.
[00:04:52] Okay, so let's put box back up here, and we'll go back to our result. All right, results is not a function, of course you're not a function. And we're gonna do the same thing we did in the exercises, we're gonna rewrite this function right below it using box.
[00:05:12] Now, the first thing we'll do is we'll put this, let's just put the string in the box. Okay, so that's the first thing we're gonna do. Then we'll map, and we'll, we'll trim the string. Please do extra trim, and then we'll map again, and we'll do Parson. Look, see, this is composition, right?
[00:05:34] Trim is going there, we got a number, we're passing number into the next thing. So go ahead and parse the ends on that. I could call it trimmed if we want. So we have a little bit more of a. Is anybody listen for that? We could do that.
[00:05:51] That's fine. [LAUGH] We could do, we got number, comes out of parse int. And we can thread that over to this thing, right? And then finally, we got this thing, where we map string from char code, and hey, look, we can just call it like that, fun. Cool.
[00:06:14] We have a box of A. And if I call the same thing there, it's A, well, we don't want a box of a we want an A [LAUGH]. So let's find one more function that will talk this out. We'll call it fold, take some function, and then, what we're gonna do is just pass the value to the function.
[00:06:31] We're not gonna box it back up. So we're just gonna say, all right, give me a function, I'll give you the thing I'm holding in my box, but we're gonna drop out of the box now. So the last thing we're gonna do is we'll fold. So we'll map, map, map, map, map, map, fold.
[00:06:45] Now we can't change anymore. Alright, there's some things to say here, but let's just like level set, take a deep breath, think about this, ask me questions [INAUDIBLE]
>> With map, you said the purpose of it was to keep the value in the box, right?
>> So another way you could do that would be to like create some state with a closure and object.
[00:07:13] So I was just wondering what's the benefit of creating a new box versus changing the state of an existing box.
>> So, I actually, you can implement this any way you want, as long as it maintains the contract of map? So I could write a class called Box, and it could have some state, and as I map it'll just change its internal state.
[00:07:34] But I want, map is only map, if it is a function, meaning if I call it twice, it gives me with the same input, it gives the same output. I have a hint that if I'm maintaining state and altering it with maps, I'm gonna get different output for input, maybe, I don't know, we'll have to see.
[00:08:15] But anyway, so I wanna call it a couple more things here. But first, let's just kind of still discuss what's happening. So what's going on is, pp here, it's like what's that the snowball of junk. [LAUGH] It just keeps accumulating state, right, nothing's connected, data isn't flowing linearly, it's that back to that procedural step by step, low level, accumulating state for each of these lines to communicate with the next line.
[00:08:50] We have to create state and just throw it out to the world. Down here, what we are doing is we are trapping it, like a fly in a jar. This X is gone forever after that map. I don't have to think about it anymore. So I don't have to worry about trimmed being used down here somewhere.
[00:09:08] It's gone after this little nap in the middle. So I'm able to contain state to where I don't end up accidently introducing complexity into my app by introducing more and more state, and never getting rid of it. The other thing is interesting, it's unifying all syntax, right? So we're calling a method here, we're calling a function there, we're calling a constructor, a binary operator, a class function.
[00:09:37] So, this is great. I'm able to take all the syntax that's like not composable and compose it into this kind of admittedly like a jungle gym of structure, right? [LAUGH] It's like we're gonna fly through this, but it's like dropping the coin in the slot and then just watching it flow through.
[00:09:55] And that makes your programs much, much, more digestible, because I don't have to go look anywhere else, or see what's happening. I know, at a high level, it's just gonna, there's nothing I can do besides flow through this. So that's really exciting. So box is a functor because it has a map method.
[00:10:15] That's what we're defining as a functor. A thing with a map method can be defined in terms of objects or other things. Mathematically, it's the operation as well as the ability to put it in the box, or how do I say that. The combination of calling map and the box tab type would lead to what we call functor.
[00:10:43] But here, for all intensive purposes, we have a linear control flow, we have a thing that we're calling a functor. It's box. It's really the identity functor. So let's go ahead and, well, no, I'm gonna leave it as box because that's how these [LAUGH] exercises got it, but the identity functor.
[00:11:01] Now these things become more and more useful, because what we're doing, in addition to this is abstracting function application. We're not calling these functions. We're given box, the function to call we're saying hey, box, call that function for me. The function call happens here within the box, right?
[00:11:20] We can do some cool stuff there. We can deal with async stuff, we can deal with errors. We can choose not to apply it. We can apply it 1000 times, whatever. And so, by abstracting function application, we're gonna gain a lot of valuable tools, and it also unifies pretty much all these ways to apply functions, and we'll see that going forward.