 So I want to welcome everybody to this month's Houston Functional Programming User Group. And our speaker tonight is Chris Bremer. He has presented here a number of times before and his talks are always fun and interesting and sort of down to earth, which I really appreciate. And today he wants to give us a brief not too difficult introduction to category theory and types. So I will turn it over to Chris to introduce himself and yeah, take it from here, Chris. Welcome. Hey, everyone. Thanks for having me today. This is actually a talk, I came up with the idea when Claude was asking for short speakers a few months ago and I was like, oh man, I think this is a talk I could give off the top of my head. But I couldn't quite get it together enough to give a talk then. But I kind of kept it in the back of my pocket and I decided that I think it's a pretty reasonable talk to give now. A few caveats. I really am going to try to keep it, well, if not easy. I want to minimize the amount of notation and the amount of new ideas that are presented. But I also want to get somewhere. I don't want to just say, hey, this is a category, have fun. I really want you to get a sense of maybe why it's useful and how these things actually capture some of the design patterns that I think everyone uses and not just functional programmers. Let me start off. So I'm going to start off with the Dramatis personae. I guess the idea is that if you kind of understand these things, hopefully you'll get a sense, you'll be able to kind of follow along with a lot of the examples in the talk. So the first actor I'm going to introduce is a type. So if you don't have an intuition for what a type is, you can think of it as being, I don't know, like a primitive type, like an integer or a string. If you like object-oriented programming, you could think of it as being my class, just an example of a class. Or if you like functional programming, I could be my record, for example. But the point is that it's not like an individual object in your code. It's sort of a general class of objects, a collection that all have sort of the same interface. If I want to actually talk about something with that type, I'll say u colon u. So this lowercase u is an example of type u. OK, types are great. We also have, now hopefully this is a functional programming seminar, so you have a sense of what a function is. So a function I'm going to represent by an arrow going from one type to another type. Again, if we have a function that takes the type u to the type v, we can say f colon u to v. Just as an example, we could have f takes int to int, f of x is equal to x plus 1. Not a very exciting function, but a function for sure. I also want to insist that functions are purer. What do I mean by that? No side effects. So the function only depends on the input or the output of the function only depends on the input. So no side effects. OK, lastly, tuples. So a tuple is just a pair of types. Now, a lot of people who use functional programming use tuples quite a bit. But if you don't use functional programming a whole lot, you can kind of think of a tuple as being the argument of a function that takes more than one argument. So f takes u comma v to w. Just as another example, we could have f takes int comma int to int, and f of x y is equal to x plus y. That's a perfectly good function, as we say. By the way, I don't know if I can quite see the participants on the screen. So if you have questions, if you want to stop, feel free to just unmute and hop right in. Perfectly happy to chat. And so the reason I like doing whiteboard talks like this as opposed to slide talks is that hopefully it gives you enough time and enough opportunity to look at the screen and then allow me to answer questions while I'm working. So that's the end of our introduction. And we're ready to start Act 1. What is Act 1? Categories. Now, you might say, hey, we're jumping into things too quickly now. The whole point of this talk is to talk about categories. But this seems like a little much at first. But if you're not, a category is pretty simple. It just consists of types, the collection of types. And again, I'll call these types u. It consists of arrows. Now, I'm going to be a little coy here. You can think of an arrow as a function. But that intuition doesn't always work. And we'll see why in a little bit with an example. With the additional properties, there's always an identity for every type. Well, the identity does, it just leaves everything the same. It behaves like f of x equals x. And we also have composition, which if we have an arrow from u to v and an arrow from v to w, we get for free an arrow from u to v to w. So just as an example, if we have f of u equals v, and g of v equals w, then we get a function here, f of g. So that composition is also associative. And that's about it. Now, one thing before I move on is I also want to insist, and this is something that maybe Neil can back me up on or complain about, I do want to insist that the arrows form something called a set. Now, I'm going to try to explain why I like things to be a set. So I think when I say set, I really sort of want you to think of, well, just a collection of objects, right? It's just a collection of things. It seems weird that I'm making this assertion here, that I want these arrows to be a set. But what I'm worried about is equality between sets. Because that's actually something that really comes up a lot. And it will come up as we talk. Can I ask you a question? Sure, sure. OK, so the category, the first sort of member of a category is the types. And you have the letter u, are you permitting other types as well, or does it have to be unique? Oh, no, no, no, yeah, yeah, so types, sorry. Yeah, so in this case, it's a collection, right? So it's like, u is just an example of a type. OK. So in this category, u and v would be two types in the category. OK, OK. And then the arrows, so you have an example going from u, arrow, v. So if I could name the arrow A. How about alpha? Yeah, alpha. So is it defined by its Rolada, the u and the v? No. No, OK. No, and the reason is because the arrows from u to v, so if you think about it like in a programming language, the type u to v, there's a collection of examples of that type, right? OK. So the example I gave before is actually a good question. We were looking at this function into int. There's actually a lot of different functions that go from int to int. It could have g, if you want, g of x is equal to x plus 2. And that's a different function. So both f and g are in the set of functions from int. Does it make sense? So it's a collection, right? So can you just consider the types also sets? Um, because the types don't have to be sets. No, OK. The types are just things. Like an integer, the type integer could be defined as the set of all integers. Yes, you're right. So yes, the types could be sets, but that's not necessary. So if you really want to be sort of like a really abstract way of thinking, it's really just kind of like a graph, so the types are the nodes on the graph and the arrows are the edges, a directed graph. So I've got a question. Sure. This is a job. So what I think about category is just what I'm speaking English. Sure. A category typically is defined by things that the members of the category have in common. Yes. Is that something that applies here or not? No, a category is just a thing. It's just a collection of types and arrows. So the most categories, yes, the most categories you want to say like from the English perspective of a category, I might want to talk about all the types in a particular programming language as being like a category, like HASC is all the types in HASCLE is sort of a well-studied category. I could also talk about the category of sets. Right. And the difference between the category of sets and the category of types is that they sort of have different, there are different functions between them. The set, a function between sets is just assigning one element in one set to another element in another set. But a function in the category of HASCLE functions has to be a function in your language. So categories, when you say like the English word of category, you're saying you want to think of sort of like a collection of objects that are defined by a shared property. But in this case, when you change categories, it also changes the arrows between different types in a category. Let me give some examples. And I think in this case, it's really worth thinking of types and arrows as being types in your favorite programming language and arrows functions in your favorite programming language, if that makes sense. So does that answer your question? OK, I hope it does. What do we mean by equality? So when I have two sets, so here's an example that I had in mind of two sets. So a set here would just be the first three numbers, right? One, two, three. And then here's another set, which is actually a set of sets, is the sets of items with one element, two elements which are exactly the same and three elements that are exactly the same, right? So these are two sets, right? This is a set of sets. This is a set of numbers. And there's a way to identify this set with this set by counting, right? If you count the numbers in this set, we get an identification with the first three numbers. So this is an example of what I'm going to call a natural identification. And we say that sets are equal if there is a natural identification between them. So I did want to give you an example of a natural identification that you're probably used to, curring. So we can express the notion of curring in a function or in a programming language in terms of these categories. So a curried function is an identification between functions from u, v, to w. These are equal to functions from u, goes to v, goes to w. So this is partial application. And what we get is f of u, v equals w. This is the same thing as f of u, v equals w. So I'm going to call it f bar. But essentially, the idea is we're going from functions on pairs, on tuples, to partially applied functions. We'll come back to this. I mean, I want curring to be sort of a motivating example throughout the talk. I did want to give one more example before we move on to Act 2, which is an example of a category. So I already gave you an example of a category, which was our example of thinking of types and functions in a programming language as being a category. There's another way to define a category, which is actually fairly stupid. I'm going to call it op, which has the same types. But we want to define arrows, u, an op arrow from u to v is just equal to arrows from v to u. So it's really stupid. We take the original category and we just turn the arrows around. You think of it if you have a directed graph, if you just turn all of the edges in the opposite direction, that gives you a new category. And it turns out it works. It's perfectly fine. So it is kind of a funny theory, because you start to get a C if you really rely on explicit examples, because the category is a pretty loose definition. Again, we'll come back to this, too. But I want to talk a little bit more about what we can do with categories. OK, quick question. Sure. For when you set unequality, is your notion of equality for categories? So it says sets are equal. Sets are equal. Yes. OK. So the reason I want to say we have equality is because I'm only ever going to worry about equality for equality of functions or arrows. And that's actually the only place where I'm actually going to use her need equality. OK. So now we're going to get into the nitty gritty of categories. This is Act 2, Functors. OK. So we've talked a little bit about functions. And I think you brought up an example of a, if we want to identify categories, for example, you'd need some way to get from category A to category B. We're actually not really going to leave the category of a particular language in this talk. But we do have a way of either transforming categories or taking one category to another category that acts kind of like a function. And this is something called a functor. So a functor is just f of u. So this is basically an association from a type to a different type. With the following properties, we have a map function. So f map takes, if we have a function from u to v, this goes to f of u, goes to f of v. So anytime we have a function, we should be able to create a new function on objects where we've applied this functor. And this map behaves well with respect to identity and function composition. So we've actually, in our Dramatas personae, we've actually come up with a couple of examples of functors that we can already sort of think about. So here's an example of a function, a functor, t of u. I'm going to put an a here. But let's not worry about that for now. It's just the tuple u comma a. So it's not really a map between sets or anything like that. We're just saying, OK, so we had this type before, but once we apply this functor to it, we get a new type, which is the tuple type, u comma a. Here a is just a, well, I mean, you can think of it as a type parameter or something like that. I'm not going to worry about it too much, but in most of the identities, we're going to sort of assume that a is just sort of auxiliary to this functor. If you want to calculate t map, well, this should take a function from u to v. Let's say we have f as a function to u to v to a new function, u a goes to v a. I'll call this f bar. And f of u, sorry, f bar of u comma a is equal to f of u comma a. So all we're doing is we're just sort of like, if we have a function from u to v, it just only does anything to the first part of the tuple. So it's a nice example of a function. Here's another one. This is a little bit more complicated. I'll call this h a. Yup. So we don't need to just think about tuples. We could also have a functor which has as output an arrow. So we can take h a of u is equal to the set of functions or the type of functions from a to u. Now, this one's a little bit more funny because if you remember, we should have a mapping from f takes u to v to a goes to u to v, a goes to v. Now, this isn't so bad. Essentially, we already have this map from u to v. So if you follow through and apply a composition, you get a map f bar from a to v. So if you want to think about it, f bar of, I'll call this g, f bar of g of a is just equal to f of g of a. So we apply g first, and then we apply f. And that gives us a function from a to v. Hopefully, that's not positioned enough. Here we go. Now, there's one more function functor that is a little bit funny, and we're going to come back to it. Again, if there's any questions, I'm trying to give a high level thing. And hopefully, you'll be able to look at these notes later and figure out, it's not too bad. So I'm going to define one more functor. So this is a little bit funny. So before we defined h as maps from a to u, we can also define a functor, which is maps from u to a. Now, this is a little bit interesting, because if we try to define cmap, if we have a function from u to v, and we wanted to find a function from u goes to a, and to v goes to a, we're a little bit stuck, because unfortunately, the arrows go the wrong way. The natural composition goes from u to v to a. So if we have a guy down here, and this function here, we get a mapping g from u to a. So this is a little bit funny, because if we rewrite this expression, if we have a map from u to v, we get a map from u to a, u to a, from v to a goes to u to a. I'll write this map down explicitly. So this map is just g of a goes to g of f of a. So this gives you a map from u to a. But what we end up doing is we just say, oh, OK, well, forget about that. This is actually a functor from the category, the opposite category. So remember, I defined the opposite category earlier. This is kind of a little brain teaser here. But I did want to bring it up. It's actually going to be useful later on. So this is the first example of a functor where we're going outside of our original category. This is something called a contravariant functor. So if you come across contravariant, that's why it's called a contravariant functor. In fact, you know what? I think it's funny. C-sharp, the latest release of C-sharp, includes covariant and contravariant inputs. So I think even if you are a C-sharp developer, you'll end up seeing some of this terminology at various places. OK. So I want to point out something funny that comes up. Hey, Chris, can I stop you for a minute? Yeah, sure, sure. Can you scroll back up there? Yeah, of course. So when you first explained the BAP, I thought I understood it. Sure. But that last one, I'm not sure I really understand what you want to. So yeah, so here's the problem is that a functor can potentially take us outside of our original category, right? In this case, this functor takes us to the opposite category. Sort of a bit of Calvin ball, unfortunately, if you're familiar with that. Yeah, I don't know what Calvin ball is. I like to impose it on people all the time, but that's all over a few. So think about it this way. I'm not actually, essentially, I'd like to talk a little bit about sort of contravariant functors. But maybe I think it's sort of a deep topic. So think of this contravariant functor as sort of a bonus content. And maybe it'll make a little bit more sense when I sort of talk about why we care about these things in Act 3. Well, it actually helps a lot to say that you could use this BAP and you end up going outside the category. Yeah, yeah. Because that, yeah, OK. Yeah, so that's the idea is that we actually ended up using that silly category that I defined earlier on. OK. But no, I mean, that's a good question. I'm really just punting on it because it's a hard question. Can I ask a question? Maybe I should ask this a lot earlier. But no, it's fine. So if you scroll up again. So all the problem with the whiteboard is I don't have a good way of navigating through the whiteboard. Well, so I was wondering when you write down F map colon and you have what look like arrows. I'm actually not sure what those are. Are they arrows or are they functions? They are set functions. Set functions. Yeah. So I am being a little bit, so that's actually a really good. OK, so that's actually another very deep question. So the point is this guy's, let me use this. This guy's a set, right? U to V. There's also a set. And F map is a function from this set to this set. So being a little bit loose, fast and loose with the rules when I'm saying this is an arrow. But in the case of the programming, if we're working inside of a programming language, this actually is fine because both of these things are actually typed. So not only is it a map on sets, but it turns out it's also well-defined in the programming language. OK. It's a little, yeah. So again, you're right. I mean, it's actually good because you sort of caught me in being a little bit fast and loose. But you're absolutely right that this is actually a morphism between sets. But when we calculate things, all the examples, we're going to see this is also an arrow in the programming language. Oh, dear. OK. So I want to come back to currying. And this maybe will give you a sense of where we're going with this. I'm going to call it currying redux. I realize it got way over my promised time, but I'm actually glad that there's lots of different questions because I like talking more than just lecturing. So remember, we stated what currying was before. Fortunately, it's right here. So here's if you look to the left of the board, you see the definition of currying. We can actually rewrite currying in terms of functors. Tu goes to v is equal to u goes to h of v. Hopefully, you can't hear that my five-year-old just started playing the squeeze box downstairs. So hopefully, it doesn't get too loud. Anyways, so this is actually really pretty cool. So I mean, this is hopefully a very suggestive formulation. Another word for this is anytime we have two function, two functors that behave like this, we call t and h are something called an adjoint pair. I'm going to explain why we care about adjoint pairs in just a second. But it turns out that these are something that mathematicians really love to work with. I actually spent a good portion of my thesis and early research racking my brain around different kinds of adjoint pairs. And certainly, Neil did as well. But they're super important to mathematicians. So there's a lot of prior art behind structures that look like this. We have another example of an adjoint pair, which you're absolutely going to hate if you didn't like the previous example. Ca u goes to v is equal to, oh, sorry. This is, remember, c is a functor to the opposite category. This is actually the same as u goes to ca. I knew you'd hate it. So ca is also an adjoint pair. We'll get back to that in a little bit. I do think it's a little bit cheeky to say that and to introduce it. But it's not such a bad thing because we're ready for our final act, which is final act, act three. Everybody's favorite monads. And I'm going to pull a rabbit out of a hat, explain why we spent all this time discussing these arrows, is because this sort of gives us the foundation for the idea of what a monad is in category three. So all the monad is it's a functor. It's a special kind of functor, mu. It has a special map, return, which is a function from u to mu. And another special map called bind, which is a function from u to mv goes to mv, mu goes to mv. OK. I'll give an example of why these things are useful. But I want to state a really cool fact first, something that I really don't see a whole lot in introductions to category three. And usually comes a little bit later. But this is a flat due to a mathematician called Pisley, which is that monads are really adjoint functors. Well, let me explain. If l, u is to v is equal to u goes to rv. So this is our adjoint pair. Then r, l, u is a monad. OK. So this is kind of a wild fact, because we haven't really talked about composition of functors. But it sort of works as you might expect. You sort of apply the first functor, and then you apply the second functor. But what's wild is that these two sort of high-falutin fancy theories are really equivalent. I'll even give you an inkling of how to prove it. I know that we're probably not, most of us haven't done a proof in a while. But let me explain really quickly. Let's say that we have u. So one of the facts about categories is we know that we have the identity map. We also know that lmap takes the identity map to some map from lu to lu. So it's actually the identity, because it behaves well under. And then finally, under this adjunction map, we get an identification from u goes to rl, u. And this is our return function. So it turns out if you follow through and do a lot of work, you can actually show that you can get the bind functor in the same way, plus all the other compatibilities I do want to mention just for completeness, plus compatibility. There are certain compatibilities between return and bind, but I'm not going to get into it. And now we have the payoff, which is why do we care about all this stuff? Well, it all comes back to curing. So curing, what comes after redux? Tredux, maybe? If we look at our previous adjoint pairs, so we had before t and h were an adjoint pair. And these correspond to the monad. Let's see. If I remember, it's ht is equal to, or ht of u is equal to functions from a to u, a to pairs u, a. And this is something called the state monad. Now, why do we care about the state monad? Well, it turns out this is the best way to work with mutable state when you're doing functional programming. So the way I like to think about this is let's say that we have an object, an object oriented kind of object. And this object has methods. So I'm going to call the object as type a. And we have a method. So the method takes this a and some input u and then outputs some v. So you might ask, well, this is a problem, because this gets mutated. Typically, when you have an object and you're applying a method, there's no guarantee that you're not going to change the object that's calling. So what we do is we then add this as an output, because the function, if it's mutating the caller of the thing, then it's reasonable to think of the caller as being another output of the function, but just discarding it. So it's actually funny. I know I gave a talk related to Matlab last time. Matlab is an example of a language that doesn't have naturally something called a handle class. So if you want to mutate your handle, which is the pointer to this, you actually have to return this as one of the outputs of the function. You can return it as a discard, but it doesn't really matter. So if you stare at this long enough, you actually see that this is really the same thing as taking a function from u to a. So this is our input goes to our output comma a. This is our output. And this is our discard. And then the bind function gives us a way to consecutively call methods on the function. So basically allows us to call multiple methods and keep track of state. So the funny thing is that if you are sort of perverse, sort of perverse, you can sort of get object-oriented, a lot of the basics of object-oriented programming out of this monad. Or you can represent a lot of object-oriented programming using this monad. OK, I have one more example, and then we'll be done. So remember, we had our other functor. So CA is an adjunct pair. So the corresponding monad is just CC of u is equal to functions from u to a goes to a. This is something called the continuation monad. Now, this is a little bit weird. But if we take a to be something like a task, then u to a is an action. It takes its input, and it does something. Given some input, you do something with that input. But you don't return anything. And then a function u to a goes to a is a callback. So when you have a function with a callback, think about it like this. You have f of u comma callback is equal to void or task. And what this is, this is a function from u goes to a goes to task. And so in this case, the bind function is really just giving us a way of combining actions and a bunch of different callbacks. So if you're used to JavaScript, especially the people who are learning JavaScript, you find that a lot of JavaScript involves a lot of callbacks. And it's hard to reason about those callback functions. But there's actually a purely functional way to think about it. And this purely functional way has a background in mathematics. OK. So that's about it. What I'm going to do is I'm going to share these lecture notes, well, with cloud. But yeah, hopefully it's not too bad. I guess when I said a gentle introduction to category three, I really wanted to avoid being bogged down and introducing too many new ideas and too many thoughts. But I also, as I said, I wanted to make it pretty far. And I feel like we got to the point where we can actually see some monads that are actually useful, things we use every day as programmers. Any questions? Well, I want to thank you so much. This was really fun and interesting. And yeah, so let's open up for questions. So I have a question. Sure. I'll start out by saying I don't really expect you to be able to answer it. But if you can, it'd be really helpful for me. Sure. Is this consumption of a monad more like Leibniz or Plotidus' monad? Ooh, you know what? It's, I don't know. I actually, I don't know. This is, to me, at least my understanding of this comes out of early category theory, which was in the 1940s, which was well after Leibniz. Yeah, it's way after Plotidus, but yeah. Yeah, so I think maybe the name, maybe there's some relationship in the name. But this is something sort of different. OK. I always wondered that, too, because, yeah, so I know monad from Leibniz. And it's, Chris, as you're struggling to make a connection, I can't possibly see a connection either. But it's such a particular word to use that it's hard to believe that there wasn't some thinking of Leibniz when this was introduced. But I think when Leibniz was talking about monads, I think that came out of its explorations with calculus, like the infinite symbol. But I mean, I don't know a lot about programming, so I don't know, I guess, how monads relate to category theory from what I've seen. Yeah, I mean, I think it certainly was influenced by that concept, but I don't quite know. Do you have a definition of what a Leibniz monad is? Well, for whatever I remember in philosophy, I think it was like some indivisible particle, like it was supposed to be like some one foundation, I guess, of a proto-atom, something like that, outside of space-time. And I guess Leibniz's philosophy, God, is the big monad that we're all connected to, and like some network or graph, but I don't know. Yeah, it was sort of an alternative to Aristotle's substances. These were more idealized. But yeah, I think so it's really hard to see what the connection possibly could be between those. But then why use the word monad? I think you'd have to ask Saunders and McLean. I mean, technically, it just means the one. Yeah, I mean, it was unary, right? Right, and it's I'm really not a philosophy kind of guy. I have a son who's doing some plus-highness work right now. And so when he started talking to me about it, it's like there's sort of a connection here, but it's hard to explain, especially if you don't know anything about Gnosticism. I definitely do not know anything about Gnosticism. So yeah, so I have this really bad habit of and Claude can confirm this of like making connections between programming things and random things outside of that. But yeah, so anyway, it was just it's just one of those things that may not bother anybody else. I know an interesting connection, I guess. Like I know a canter who developed set theory. He was interested in like Leibniz and Kabul stuff like that. Yeah, I mean, I'm not a mathematician, but I know from what I hear about category theory is supposed to be a better foundational theory than set theory from what I've read. I mean, well, I have an English and history major, so none of this stuff makes any sense to me. Well, I mean, so one thing, I don't know, I tried to get this idea across in the previous talk that I gave here using computation expressions. Computation expression is the way F-sharp represents monance in its language, is that in some ways, if you think of a language as being from the point of view of an object-oriented programming philosophy, your grammar is quite limited. If you have an object, you have only a certain number of methods that that object can handle. When you're looking in terms of a computation expression in F-sharp or monads, you can consistently sort of, it gives you a way to string together methods in a coherent way in the same way that you can kind of concatenate words in a sentence. And that's kind of how I like to think about it. So I think there's certainly a grammar aspect that this talk doesn't capture. But I do like to think of things in terms of language. And maybe that's a different talk that I could do, monads for English majors. That would be pretty awesome. But yeah, I don't know. My hope with this talk is that if I can kind of pare it down or practice it, it might be something I could give elsewhere at another meetup or a conference or something like that. So thank you for being my guinea pigs. I don't know if it was as kind of an introduction as I had originally wanted it to. But maybe having given it once, I can work on that. I seem to remember you saying something about fitting this on a napkin at the last meetup or something like that. And I've never seen this kind of napkin. So that's a good question. You can see everything on if you were to unfold the napkin into four parts. Right, right. You could probably do this. So yeah, that was the original goal for the talk. But it becomes a bit of a trade-off, right? So one thing when I give talks like this, I really do like board talks because I think that they help with pacing and help prevent you from sort of trying to put too much into a single slide. But they do sort of slow down the pacing. And then the other trade-off is I wanted to give you sort of a full story where we started with some abstract concepts like arrows and types and some kind of pictorial math and then end up with something that I really do think that we do use every day as programmers. I think thinking of methods applied to objects is really being an example of a pretty standard monad. And also thinking of callback functions and actions as being a different kind of monad are useful, especially since they tie in with currying, which is somehow the font of both of these very commonly used monads. But it is also sort of something that's considered central to functional programming. I think I have a question. You were talking about the op arrow as being just the essentially, is it flipping the, like if you have U2V, it's VDU, essentially? Yeah. I know a lot of times and for practical purposes, when programming, like say V was an int and U was a decimal number, VDU is not equivalent to going the other direction. So if you converted the decimal to an integer and the integer to a decimal, it's not like the initial integer is going to be the same as the final integer. That's true. Here's a counterpoint to that, though, which is you're absolutely right that, for example, int goes to decimal. It's sort of a standard embedding, but then decimal to int is not your right. You need some sort of rounding. So it's not necessarily the same arrow. But what happens is, is if I want to say maybe if I have a function which says, let's say I have width of a div, so width takes integer to a div in HTML. So here, I'm just trying to understand like a layout of a screen. It's also possible to, sorry, it's possible to get a width from a decimal to a div. Sorry. I think I did things backwards, which is sort of apropos. Let's say that we have a mapping from decimal to div. This gives us an automatic mapping width takes int to div, which is inherited from our mapping from decimal to div. And it's basically just taking the coercion from int to decimal and then taking that to div. So this is a funny situation where our original map from int to decimal actually gives us a map in the opposite direction from a width function from decimal to a width function from int. Does that make sense? That's our op function right there. OK, well, anyways, we can talk about it more later. I need to take a quick break, but I'll be back for more discussion and more questions. Well, on that note, I think I'll then stop the recording. And yeah, then we can talk when you get back. Awesome. Thanks so much. This was great. Thanks, Chris.