 Okay, happy Monday everyone. First off, apologies to everyone who's watching online. I did not bring, forgot the mic. So you have to deal with the microphone that's right here. So that'll be fun when you watch this lecture later. Oh, let's see, midterm next Monday. Practice, you did not require a response, but thanks. Let's see, you'll get your midterms back before then. Sometime this week. And then there'll be a practice midterm out later this week, but we need to cover Lambda calculus stuff so I can give you a practice midterm that actually makes sense. Any questions? Project fives up. Go, go, go. Cool. Okay, so we are going over Lambda calculus. So what we're trying to do right now is to build up some intuition on what does a Lambda expression mean? What does something written in Lambda calculus actually mean? So we saw that what we have here is Lambda x dot plus x one. So if you were to disambiguate this, where would you put parentheses? So let me give me one set of parentheses. Okay, one after the dot and where would you put its corresponding pair? After the one, right? So our first rule is anything from a dot tries to extend as far to the right as possible. Great, what about the next one? Plus and x. Yeah, there should be parentheses after plus and x if we wanna be completely unambiguous. Cool. But the whole beauty of having these disambiguation rules is we don't have to do that explicitly, right? When we see a Lambda expression that is Lambda x dot plus x one, we know exactly how that goes. And so as we talked about on Wednesday, this represents a function that adds one to its argument, right? The way to think about the Lambda expressions, right? Is there an abstraction? You can think of them as functions over some variable x as a parameter and it's returning plus x one. And so if we applied this abstraction and basically added a two after it, but why do we have to add parentheses here? What happened if we did not have these parentheses? Yeah, it would include the two, our disambiguation rules would mean that the two is included as the body, right? So this is not a function application, but here we have Lambda expression, Lambda expression separated by a space, which means this is a function application. So we're actually trying to call a function. And when we do that, we're essentially gonna replace in the body the x with two. And so it would eventually reduce to three. But as we've seen, okay, if we're trying to think about Lambda abstractions, if we're trying to think about abstractions as functions, right, this Lambda x dot plus x one, we don't have a way where we can say Lambda x comma y to say we want a function that takes in two parameters. So why can we define plus if abstractions only accept one parameter? How many parameters should the plus operator or function take in? Two, right? Should take in two parameters and return one thing. So it turns out the result is we're not gonna go in, we're not gonna prove this or anything. It turns out the result that Curing is a technique to translate the evaluation of a function that takes in multiple arguments into a sequence of functions that each take in one argument. And the really cool thing about this is this basically means that a language that can take in multiple parameters for a function is equivalent to a language that can just take in one parameter for a function. And so we can define a function like this. So this is a Lambda expression that basically does addition, will add two parameters. So the way to think about this is so we have Lambda x, so we have one abstraction and the body of this abstraction is this whole body, right? This whole thing here. But the body of that abstraction is Lambda y dot plus xy. So when I call this and I pass in, let's say, the parameter one, what's it going to return when I evaluate this? So first off, what do I do? I mean, we're gonna go into the exact precise steps later. But at a high level, what is this going to return in some sense? What is it gonna return? It's gonna return Lambda y plus one y. So what we're gonna do is replace inside the body here, we're gonna replace all the x's with one. And so that's gonna return Lambda y plus one y. So you can think about this is a function that returned a function, right? So it's a big function. We evaluated it the outside function and it returned us a function and it specified, hey, in my body now, instead of x being some random thing, I know x is one. And so now if, and that returns a function. So this returns a function that adds ones to its argument. So if we apply this again to something like two, it'll finally return three. So we can do this here. We can say, okay, now what happens if I do this? So is this, so first what's gonna happen, right? We know with our disambiguation rules, application is gonna be left associative. So this is going to happen first before the outer one. Everyone agree? Cool, so we do exactly what we did here. We first are gonna replace all x in here with 10. So this is gonna return Lambda y dot plus 10 y. Now we have another application, right? We have a new abstraction, a new function. Now we can replace y with 20. And now we replace y with 20 and we get plus 10 y, which we're adding 10 and 20 together. And now we're going to eventually get 30 if we were to expand that out and do all of that. So super cool way to think about it. So instead of thinking about one function or one abstraction that takes in multiple parameters, we're essentially gonna have nested functions like this. So if anybody's done any Haskell programming, maybe F sharp, I'm not super into F sharp, but you can do this with any kind of function. So even though the functions take in multiple parameters, if you just pass in one argument to a function, you get a new function that takes in one less parameter. And you keep doing that until you supply all the parameters and then you get your result that you actually want. Questions on this? So this will really help you to read Lambda expressions. Right, when we see Lambda x dot Lambda y, you can think of this as a function that takes in two parameters, x and then y. So it'll become more clear as we go through more examples and start cranking through how to actually do these. Questions on this? Cool, Korean, it's awesome. Okay, so now we need to talk about different types. Actually forget, did we talk about bound and free variables yet? I don't think so, no, okay, that's what we're gonna do here. Cool, so we need to make two definitions of when we see a variable, when we see an ID, what kind of variable is it? And the way to think about it is this. It's gonna depend on the exact scope that we think about. So given a Lambda expression, we wanna know if a variable is free, that essentially means it's a global variable. If it's not free, we'll say it's bound and that means it's basically, it maps to an argument of a function. So this gives us a nice way as we'll see when we start computing these things formally about how to actually do these reductions in this computation. But for right now, we're saying a variable is free if it does not appear within the body of an abstraction, so it's not within the body of an abstraction with the meta, that has a meta variable of the same name. So is X free in the Lambda expression Lambda X dot XYZ? Why not? Yeah, so it appears within the body of an abstraction that has the meta variable of the same name. So if you think of this as a function, you can think of X as essentially a local variable. It is bound to the parameter of a function. I mean, local variable maybe is not the right way, but it is the parameter of this function. What about Y? Yeah, so Y is free. Y could be anything. X always, in this thing, X always has to refer to that parameter. It's not gonna change. X always refers to that parameter, but Y is what they're called free. What about this? Is X free there? What does the definition of free variable say? Yeah, so the part of the problem is there's two Xs, right? There's an inner X inside here. Is this X free? No, this X is a bound X. Is this X free? Yes. Right, so this X is inside the body of an abstraction that has a meta variable of the same name. This X is not inside that body, and it's not inside the body of any abstraction, and so therefore that X is free. So if you had to do something like circle or identify free variables, you would circle this X on the right, but not this X on the left. And depending on what one is, right? We don't actually know what one is, so maybe there's some free variables in there. What about Z? Is Z free? No? So how would you read this as a function that does what? That takes in three parameters, and what does it do with those parameters? Yeah, kind of, so you think of X is the leftmost, so that's gonna be the first parameter. The second parameter is going to be Y, and the third parameter is going to be Z. So you can think of, all it does is rearrange the order of those three, right? It was X, Y, Z, and that's gonna flip it and do Z, Y, then X. So it's actually just a cool way of kind of moving things around. Cool, what about this? Is X free in here? I mean, here, let's look at this. Sorry, and I also don't have my handy-dandy drawing thing, so I'll have to go with this. What I mean is if we have this as a lambda expression, and let's say we also have after this, let's say one, two, and three, well, it's kind of tricky, but let's say we first apply it to one, and that'll return, let's say this with a one here, and then I apply it to two, and that'll return the middle with a two here, and then I apply this to three, then it'll do three, two, one. So even though the parameters were in order one, two, three, the end result is three, two, one, what it's going to return. Now, whatever those things do, we don't know. They could be any arbitrary functions or nothing, they could just be variables, but we know that they're gonna happen in that order. So if you think about it, if you wrote it like this, one, two, three, right, the one and the two are grouped together first, well, actually technically it'd be like this, like this, and then this, and then this, so when we return, we return something that looks like this, but I've kind of shuffled those orders around. Anyways, yes? Yes, good question. So if I had done, which why I didn't do that at first, but if I had done like this, one, two, three, which we know is actually like this, right? So if I had done this, now I'm replacing in this body X with my first parameter, which is one, two, three, cool. Okay, so back to our original question, is X free in this lambda expression? And we can see that the light's working, it's no longer blue, that's nice. Was that for yes, the thing is no longer blue or yes, that X is free? It's free, right? So inside this body, remember this body only extends all the way to the end of this right parenthesis, so this is the body of this abstraction, right? So if there was an X to occur in this body, it would not be free, it would be bound here. In this other abstraction, here we have X, but the meta variable is Y, and so this X is a free variable. Cool, questions on this? Free, free variables? Yes, yes, so if we were to reduce this, right? So the question is, A, is this a valid lambda expression? Does this correspond to our syntax for lambda expressions? Yes, right? Then the next question is, okay, what type is it? It's an, as we'll see, it's an application, and the thing on the left of the application is an abstraction, which means we can reduce it as we saw, we haven't gone through and gone through what exactly those steps are, but yeah, what we would do is we would return Z foo. So this X, because it's not used anywhere, basically consumes this argument, gets rid of it, and then we have Z foo as the return here. All right, so the rules, so what we're gonna do is we're gonna go through, and just like we had rules for syntax of the different types of cases, right? We wanna be exhaustive when we have a definition of what does it actually mean to be a free variable, and as we'll see, these are gonna mirror very similarly to our rules of our syntax. So X is free in some lambda expression E if X is equal to E. So if we just have the expression X, we know that X is free, right? It's not in any abstraction. We know that X by itself is free, agree? So what about the case where the expression is a lambda is an abstraction, but the abstraction variable is not Y, or is not the same thing as the variable we're interested in. So let's say this expression is in the form lambdaY dot E1, or E1 is the body of this abstraction. So X will be free if X is free in E1. So what does this in essence say that we can do? Yeah, if the meta variable isn't the same name, we just ignore and return whatever the body says. So this would be if E1 is X, then we know from here E1, X is free, and so we know that because this is lambdaY that doesn't change anything, right? Because we're not bound, X is still free no matter, well, if this meta variable is not the same thing as X. But it could be anything, right? Any meta variable name, just as long as it's not the same thing as X. Cool? So then what's the other case in this? If it's equal to X, well, okay. Damn. All right, but if it is equal to X, then what should the answer be? Not free, right? It can't be free because there's a lambdaX. But here we're defining when X is free, right? So, oh yeah, so we have the different cases. We have application, right? So a lambda expression could be E1 space E2. Does that affect our free variable decisions? So if we have an application, we say if X is free in E1, does that mean X is free in the entire expression? No? Yeah, we've already found that X is free in one side of the application, right? So if the left side is X and the right side is Y, right? This is saying that X is free in the left side. Therefore, shouldn't X be free in the entire expression? Right, just like we saw on this last one here, right? X is free on the right of the application, so that means overall X is free, right? We just need to find one instance. That's the way to think about that. Cool. So if it's free on the left, then X is free. If it's free on the right, X is free, right? This is pretty straightforward. So basically what this means is an abstraction doesn't change anything in terms of free variables, right? Because free variables all we care about are abstractions. And that's all we have. So we could do parentheses, but parentheses don't change things either. So basically what this is saying is, right, we can only say yes if inside of an abstraction, the meta variable is not the same thing as the variable that we're interested in. Otherwise, we just say, hey, then it's not free, right? So this is just formal definitions of our intuition of what it means to be a free variable. Any questions on this? Yes. Does that match any of our cases? It does, which case? If it's lambda X dot something, yes. So if X is equal to Y, if it's not equal to Y, as long as X is free in E1, then it's free overall, right? What this line says is, hey, if the meta variable is not equal to X, if it's free in E1 in the body of the abstraction, then it's free overall. If Y equals X, does that match any of these cases? No, so it's not. So what we're defining here is when X is free. So we'd go through all these things and say, okay, the expression is not X, the expression is not lambda X dot E1. The expression is not an application, and so it'd be false. In this case, if it's exactly X, so the question is, right? So is this a lambda expression? Yeah. And so it matches this case, right? Of just X. So we'd say, is X free in this expression? Yeah. Is X free in this expression? No, it doesn't exist, right? It's not free, there is no free X. There's no free X, there's no bound X, right? And so that's because it doesn't match any of these conditions. We'd say no, it doesn't match any of these conditions, right? This is the case where it's just an ID and it's exactly what we're looking for. I don't care, I don't know. So what the second rule basically says is hey, if there's a lambda X in here, then I don't care X, Y, Z, A, B, C. I don't care about what's in this body. I know this is not, X cannot be free in here, right? Because there's a meta variable of the name X. It's not possible for that to be in there. But if this is part of an abstraction, or if this is, sorry, if this is part of an application, then yeah, I have a free X here. This X here is free, okay. So using this as X free here, yeah. And we could break this down by each of the rules and eventually we get to an X that is not inside of an abstraction. And we'd say yes. What about in this? And this, oh, no, right? This is in the body of the abstraction. So we never go into that abstraction, cool. So combinators, basically this is a way for us to talk about essentially functions. So combinators are, of course, another term, well, like in many things in Lambda-Cogulus, there's like a direct analogy to programming terms the way I think about it. So a combinator is a function, or is, okay, the technical definition, it's an, is that right, yeah. Expression is a combinator if it does not have any free variables. That means no variables are free. So you can think of it as a function definition that does what? So what is the free variable analogy to regular functions in programming languages? Or not programs, regular programs. Global variables. So if you define a function with no global variables, then what is it? I mean, there's not a specific term for it, but how would you, you know, it's actually more of a mathematical function, right? Its output is only the, is only ever based on its input, right? And actually, hopefully some of you have learned maybe that lesson in a painful way. The more you can minimize your usage of global variables, the easier it is to reason about your own programs. Right? Because you don't have to worry about some function over here modifying some global variable in a weird way that over here, then breaks your code into completely unrelated areas. If every function has just returned something based on its input, then it becomes a lot easier to test each function in isolation. So you can be sure that each function actually works. This is something you should think about a lot more and try to apply your own programming. So in Lambda Cagulus, we have a way to talk about this because we defined free variables. So we'll say that any expression is a combinator if it does not have any free variables. So we can ask questions like, is this expression a combinator? Yeah, no free variables, right? All variables inside here, all IDs are not free. What about x dot x? Is it an interesting function? It's the identity function, it just returns whatever it's passed in basically. What about Lambda z, Lambda x dot x y z? Why not? Right, y is free, cool. This is gonna come up, this is gonna be actually really interesting. There's a whole, we'll see that most of the interesting functions we wanna write, like when we start doing Boolean arithmetic and start doing ands and ors and true and false, those are all gonna be defined in terms of combinators. Similarly with math, we're gonna find plus and minus in terms of combinators and also all of the integers in terms of combinators. And there's a super interesting combinator that we'll study later, but I'll leave some suspense. So the opposite of a free variable is then as we've been alluding to a bound variable, right? So you can think of this as the parameter to a function. That variable when you use it, you know exactly where it comes from, right? It comes from that function definition. So the easy way to think about this, if it's not free, it must be bound. If it does not exist in your expression, then you don't care. The question though is just like scoping rules, right? When we talked about scoping rules, we always wanted to say, okay, we see that this variable is used. What declaration does it map to? And so that's the question we also wanna ask here is, it's bound by what abstraction? So we know that this variable is bound. It means it must be the parameter to some function, but which function is it? So what would be, so let's say we have a case of, man this copy paste is awesome, okay. So where would this x do you think would be bound by? Which one? Yeah, the second function definition, y. Why is that natural? Maybe, so where does this x bound to? The outer x, and this x is bound where? Here, right? So what about scoping rules? Does this have any analog to scoping rules? What about scoping rules? Yeah, we look closely, right? We look and see, when we're trying to map a variable usage to its declaration, we first look in the local scope, and then we look one scope out, and then we look one scope out, and then we look one scope out, and then finally we look in the global scope, right? That's exactly what we're doing here. So this is something that you've been doing forever. You just have to try to map your ideas of programming into this weird-looking parentheses and lambda language, right? So here I see this x, I need to look and see what abstraction is this bound to. Well, I look at the innermost abstraction, and I say it doesn't have the name x. If it does, then that's where it's bound to, and if not, then look out in its abstraction. Is that named after? So if not, keep looking out until, if I find one, then that's the abstraction, otherwise I say it's not bound variable, it's a free variable. So if I change this to y, right, now which x is this bound to? Is it a free variable or a, right? This x is bound here, cool. So now going back to our, building up our intuition about what these things actually mean. If I put one in here and I wanted to try to reduce this, what happens? What does this return? What should I do, like this? Should I change this to one, right? So remember that what we talked about informally was, hey, let's replace every x inside the body with this parameter, right? But really that's why we were talking about it imprecisely, right? Because we haven't developed the language to talk about it very precisely. We don't wanna replace every instance of x in here. What do we wanna replace? Every x that's bound to this x, right? We wanna replace all of these essentially uses of this function parameter with the parameter that we passed in, right? This x is bound to this x. It basically has nothing to do with the outer x, right? It completely shadows it. Just like when you have a variable that you've used inside of a smaller scope, if it has the same name as something in the outer scope, it shadows it and you don't care what that is or what it refers to, you can never refer to it. Yes, I wouldn't phrase it like that. We'll see exactly the way to think about it is if you take off one layer of this abstraction of this outer x, so if I look at just the body by itself, are there any free x's in this? Yeah, there's a free x, so we replace all the free x's with the parameter, right? You gotta think, it's actually a very cool way to define it because all the free x, if you essentially strip off, so now are there any free x's? No, so it's kinda cool. If I strip off this function definition by one, now any free x's in here must have been bound to the outermost x, and so I'm gonna replace all of those free x's with one, with whatever the parameter is. Does that make sense? Cool, we're getting a little bit ahead of ourselves, but I think it's good. So, this is what we're looking at. We wanted to find, remember free variables are really easy, you just say yes. They don't refer to anything, they're free, right? But once you're bound to an abstraction, you wanna know which function are you bound to, right? Which function meta variable are you bound to? So, just like before, we now have rules to do that. And this is exactly what this says, so this is gonna be just what we talked about right now with essentially stripping out the body of the abstraction and actually seeing who's free. This is the same logic here, so we say, if an occurrence of x is free in some lambda expression, so there's an expression, you have a free x in there, then if you throw a lambda x around it, it's gonna be bound to that lambda x, right? So, this is the way to think about this, is exactly like this. So, if you, I don't have a good way to do this, maybe, well I can't jump up there, maybe I can. But basically the idea is, if you have an abstraction, if you take away this outermost, what was that so much? If you take away the outermost abstraction, any free x's are bound to that lambda expression. Just like here, if I take any x, y, z, right? X, y, and z are both free. But if I put a lambda y around this, then now y is bound and it's bound to this abstraction. Now, is there a lambda y that is free in this whole expression? No, therefore if I add a lambda y dot y here, this y is not bound to the outer y, it's bound to the inner y, because it was not free. Does that make sense? What is free inside here? X and z, so let's say, now if I take this, and I throw a lambda z around it, is z bound? Yeah, and what abstraction is it bound to? This one, z is no longer bound, so if I throw now a lambda z around there, that z is not bound here, it's bound to the inner z. Does that make sense? It's kind of weird defining it in terms of throwing a function around a body. Yes, what example? Which example? This one right here? This? Yeah, so the idea is inside here, so if we take this by itself, right? We say, are there any free x's? Yes. Then if we put a lambda x around that expression, then where is that free x bound? To this abstraction that we just made. The other way to think about that is if you have a lambda abstraction and you're trying to say, what is bound to this x? Well, it's easy to figure out. You just get rid of it and say, what's free? What, sorry, not what is free. What x's are free in here? Those must be bound to that abstraction. So that's the way to think about it. You can think about covering it up with your hands if I can't really do it digitally. Okay, so this is saying that if we have an x, this just means whatever we throw after it doesn't matter, right? So this is saying if an occurrence of x is bound by a particular lambda x in E, so inside our expression there's a lambda x that binds this x, then it doesn't matter what lambda z dot expression, lambda x, lambda a, lambda beta, just like we saw, we can keep adding abstractions. It doesn't change that binding, right? This basically says the binding happens the closest it can. So even if z is equal to x, just as we saw, we can keep adding lambda x's and the innermost lambda x is going to bind that x. So by this we can see that this x is bound to this lambda x, and it doesn't matter if we add more lambda x's, it does not change that binding. And this just says that if we have an abstract, if we have function application, E1, E2, E2, E1, it doesn't change things, right? All we care about is function abstractions. Cool, let's go through some examples. So what's bound to what? So what is this x bound to? This x, what about this x? Hmm, this y, here? This x is bound here? Here? What about this y? The lambda y, what about this z? Free, what about this y? Lambda y, what about this x? So this x, what about this x? And the y? Also free, cool. So let's see if this is right. All the free variables should be underlined, all the bold variables refer to the same x and all the italicized variables refer to the same y. I think that's what you said. Let's say it is. x is a free variable in this expression, y is a free variable, and z is a free variable, exactly. Question is which one, right, I mean? That's another thing. Yes, as long as it's free anywhere, when asking is x free in this lambda expression, you just need one. What if I said is this x free? The answer would clearly be no. Okay, so this x is bound where? This outer x, the y is bound here, what about this x? Free, and this z? Lambda z, cool. I think, what do we have here? So this x? Outer this x, that's the meta variable this x? Inner, what about the z? Free. Cool, sweet. Okay, so now we're starting to get a feel for how to call functions, but there'll be some, as we're doing these substitutions, we haven't got there, but there are definite ways where we can mess up substitution. So actually, let's start to think about that, because I think that'll make things easier. So let's say I have, okay, is it gonna be confusing to have all these? Let me say we have lambda y in here, and then we have x, y, something like this, cool. So pretty easy function, right? So let's say my parameters are one, no, let's say they are, so my parameters are, if my parameters are one and two, what is this going to return? One and two, right? So the x is gonna be substituted for, this x is gonna be substituted for one, this y will then be substituted for two once we reduce that, right? And so that will result in one and two. So by that same logic, what should this give us? Y, x, what does it give us? So let's substitute, just like we've been talking about, we're gonna substitute this x for what? The y, and so we're gonna return this, substituting that x for y, right? And the important thing to remember is this is its own thing, and then we have the x. So what is this return? X, x, so what was the problem? Yeah, so with this y, what is this y? Is it free, is it bound? What about this y? And then when I substitute and change this x for here, what happens now to this y? It's bound, it's no longer free, right? It used to be free, but now we stuck it in there and because there's this abstraction around y and it's just that we happen to be using the same names, now we've messed everything up, right? So this is why we start off with that really simple intuition about, yeah, yeah, you just substitute things in there, but the reality is a bit more complicated. And so to help us deal with this, I want you to think about what's the difference between these two things? So this is a function that does what? It returns itself, so if I call this with one, what is it gonna return? If I call it with two, what is it gonna return? If I call it with, I don't know, ABC, it'll return ABC, right? So what is this function return? It's first parameter, exactly. What is the difference between this function and this is kind of a philosophical question? And this function, are they the same? Let me tell you more, they're not the same. Yeah, they're not texturally the same, right? If you take this one string and then you look at this string, are they the same? No, they're clearly different. But if you give them the same input, will they give you the same output? And is that true for every single input that you could possibly give? Are you sure? That'd make you doubt your reality? Then we'll give what? Will it ever give Y or X as output? So if I pass in X for both of them, what are they each gonna return? What about Y? What's the only difference here? We've renamed the meta variable from X to Y. And so this is what we need to talk about now before we really get into how we do these substitutions and actually perform this calculation, is because we wanna talk about, well, what does it mean for two functions to be equivalent? Right? Just like we saw, is lambda Y dot Y, is that the same thing as lambda X dot X? I mean, it's clearly not exactly the same thing. But conceptually, you could think of the input spaces for all these functions will map to the same outputs. What about this? Lambda X dot XY and lambda Y dot Y X. So there's still not the exact same string. So what was changed? So was the function parameters renamed? The meta variable, like in the first example? Yes. But are they the same function? So you're shaking your head, why? They have different free variables, right? They each refer to different global variables, right? So if you passed in, let's say, right, we have this function here. We pass one in, what is it gonna return? One Y. And then I have this function here. And I pass in one, what is it gonna return? Is one Y and one X the same thing? No, they could be, but are they always? The problem is it depends on what X and Y is, right? So here we have two functions and even though we've changed the parameter names, like we did in the first case, we've changed the global variables that they rely on. So then can we say that those are equivalent? Why no? They return different things. They'd only be equivalent if X and Y were always the same thing. All right, what about lambda X dot X and lambda X dot X? Very clearly they're the same. They are literally the exact same string. They're the same function. If they're not the same function, something's horribly wrong. So we're gonna define a notion to capture, hey, in this case, these two functions are what we're gonna call alpha equivalent. They're basically the same function just with renamed parameter names, but these functions are different functions, right? These functions are not the same function because the free variables have changed. So the way we're gonna do this is we're gonna, I'm gonna just go through this real quick since we've already gone through all the intuition. We're gonna use this equal and the alpha operators. We're gonna say these two lambda expressions are alpha equivalent. If we can replace all the meta variables of one and get the other, but we need a way to say that, to replace all the meta variables of one and get another. So we need a way to rename variables in an expression. So we're gonna see that we have to do that and we'll see that on Wednesday.