 Thanks, everyone, for being here on the day before Thanksgiving. You're definitely going to have a leg up over your classmates who chose not to come, because this is going to be difficult-ish stuff, and we're building on it for next Monday. First, any questions? Project 5? Other stuff? Yeah? On the answer credit, is it all or none? No. It's like the other ones. Are you really going to want a quarter of five points? Hey, that's all you can get. I mean, better than zero, I guess. You're not going to include any error cases where you put variables inside the body that aren't inside the definition. So every program you're going to get is well-formed, just like all the examples. You think that's not the case, then say something. Yeah, exactly. Is the deadline the same as Project 5? Same day as Project 5 submission, so same day and time. So let's have a week at midnight. Other questions? Run every homework six. There'll be a homework on landing calculus, because it's going to be on the final, so you want to do a homework on it first. Not sure yet. It'll probably be after. It'll give you some breathing room between project and homework. Obviously, sometimes between Project 5 and before midterm. So that way you can get the answers back and everything. That should be good. Yeah. Watch it. Did you just say we're getting our test back before we get it? You should, yeah. We want to have the test midterms graded by Wednesday, so hopefully that happens. Otherwise, if not, we'll figure out some way to get all 200 of your tests to you. Yes. We already have midterm one, midterm two. There's no difference. It's going to be the landing calculus, which we'll have the homework on, so it doesn't really make sense. We'll probably have five questions. Like, seven of you in office hours? We don't have the same question. Because it's easy and everything's done, right? Okay. It's the holidays and we're ready for it. What? You're going to work on it really hard in the next week? Good. And you've been working very hard on it? Great. Okay. So, we're back at landing calculus. Right? So what do we say? What's a fruit variable in landing calculus? Like, without defining it. Like an informal definition. Yeah. Say what? Yeah. So it's not inside of an abstraction. It's not inside of a body with a meta variable of the same name. Right? So it's not referred to by any of the abstractions. Let's go full on review. So what are the three different forms that a lambda expression can be in? What was it? E. Which is what? Expression. Expression. Expression. Expression. Space expression. Yeah. What did we call that? Did we give that a name yet? No. Okay. Good. Application. Application. Yeah. Good. Okay. What's the next one? Like the easy one. Yes. So parentheses to force grouping. So it's lambda variable dot expression. Yeah. Lambda variable dot expression. What did we call that? What was it? An abstraction. An abstraction. Yeah. Also a function. But the landing calculus term is an abstraction. And there's a fourth one. Yeah. Expression goes to ID, which is just some kind of variable. Right? Cool. All right. Look at this. All this knowledge retained. It's been a few days. It's very good. Okay. So what does it mean for X to be free in an expression? What are the rules we have here? So how many different rules do we need? At least four. Four. Right? We need an expression that can be in one of four forms. Right? We can drop the parentheses because it really cares. It doesn't really matter for semantic purposes except for grouping an expression together. Right? So we have three things. So what about if the expression is the IDX? Would that mean X is free or not free? Yes? Yeah. It means that X is free, right? So if the expression is just the identifier X, then X is free in this expression. Right? Why? Yeah, it's not inside any abstractions. Exactly. Okay. What if the expression is of the form lambda? We'll say another variable Y, epsilon 1, or E1. Sorry. Yeah. So we need to check, right? So we're going to recurve. So the rule is, okay, well if the expression is an abstraction and the meta variable of that abstraction is not the variable we're interested in, then we have to look inside that expression to see if there's a free variable called X. Do we go over this? I feel like we... Oh, we did not go over this. Oh, because we started here. Okay, this makes more sense. That's why that sentence isn't finished. That's weird. Okay. Okay. Cool. Okay, so we've been looking at... So this is actually where we stopped with all the examples. Sorry about that. We already went over these. We talked about which ones are free and which ones are not. So these are the definitions that I thought we were reviewing, but instead you guys actually derived them very well. So that's even better on your part. Maybe I'll do this every time. Okay, so variable X is free if expression is X, right? If it's just an identifier, then identifier has the same name as the variable we're interested in, bam, it's free. If we have an abstraction and the meta variable is not named the same thing as the variable we're interested in, and X is free in E1, then X is free. Right? So this means we're actually recursing into E1. Sorry. Some of you guys have been asking me questions at office hours about first and follow sets, and I've got like epsilon and lambas mixed into my brain, and it's very weird. Okay. So, it's not complete. Let's put it on the back burner. Okay, let's say, okay, so it's pretty clear if it's an application, right? This third rule. So if an expression is an application, then we say, well, if X is free in E1, then X is free, right? Which is what we've seen. So if it's free in basically either of these E1 or E2, then we know that it's free. It's gonna bug me. Okay, so we have E. So here we're saying X is free in E2. Yeah, X is free. Yeah, that makes sense. I think these are the only rules. I'm not really sure what this end of recurrence is supposed to be. Right? So if it's an application, if it's free in either the left or the right, then the variable is free. Right? Which makes sense. So I really see how these definitions are recursive. Right? So how do we tell if X is free in E1? If it fits any other rules, right? So we pull it apart and keep on recursing just like we say, hey, X is free in E1 here in the application or X is free in E2. It's super simple. So I guess the one case here that's not stated, right, is when X is not free because we're trying to determine if X is free. So what would be the case where X is not a free variable? The expression. Yeah, so exactly. So when the meta variable is named X, then we know X is not free in that expression E1. Exactly. Yeah, does that make sense? No, because clearly that's the definition of free variables. OK, fairly simple. All right, let's look at some concepts. So is X free in this lambda expression? Yes? No? Yes. Why is free? Because if you look at that, the one where it was E and E, if it's free in one, then it's free in the model. Right. So how do you parse this? What's the first top of expression? E. Which are the rules? Yeah, E, E, right? So this is an application. And then lambda X dot X, right? And that in itself is an expression which has an inner expression of X. Yeah, exactly. Exactly just from applying those rules, right? We can easily do this. So we say, OK, here's the whole thing. How do I know if X is free here? Well, if X is free in here, then that means X must be free in either of these expressions on the left and on the right. And then the left one is just the ID X. And we know that that's good. So that is free there, yeah. What does it mean for X to be free? What does it mean? What does it mean? What's the implication? We're getting there. We're building up our base of some terms that we need so that we can use them to define basically the computation. It means that it's not in the body of a lambda that has the same meta-variable, right? In the definition yet earlier, I'm just having trouble figuring out how the rules apply based on where we're going. It should be clear, but let's see. OK. I can wait. OK. Cool. Yeah, OK. Something like an unused variable? How do you define unused? I think it has a pattern. We could define it somewhere else. But if it's defined somewhere else, it's having its unused. Yeah, so that's kind of, I guess, the sneak peek. It's having a global variable in some sense. Because to find somewhere outside of this function is one way to think about it. So if it's looking at the rules so that you apply it independently, so if x is free and one of them is not, say it's free and you want, then we're good? Yeah, so this is the important thing is, we're just talking about the name x. So x could appear multiple times. It could be in multiple meta-variables that all have the same name x. Exactly. So all we're saying is, is the name x free? At some point. Exactly. At anywhere in this expression. Cool. OK. Is x free in this expression? Yes. Lambda x dot xy, x. Yeah, right? Because it's free in the right expression. So everybody see kind of how you, well, the body here is only xy, right? So this is y. So this x in here is not free. Yeah, we'll get into that in a second. OK. Is x free here? x is free. Why is x free? If I were to add parentheses here, where would I add the parentheses to disambiguate this? After the y. What was that? After the y. Where would I add the left parentheses? Oh, before the lambda dot. For the lambda? No. For the y in the outer. Right. Remember, so application is left associated. Right? So in that case we group things to the left. But here the body extends as far as possible, as far as it can. So here this body is going to extend and capture both of those things here. So this is one of the times where the disambiguation rules really help us figure out is this a free variable or not. Right? Because here if y and x are part of the body, then it's, is it x free or not free? Not free, exactly. Correct. No, no, no, it is because this x, so the body extends as far right as possible, but can it extend past this parentheses? Right, which is not free, but is there, so we're talking about a whole expression, you just want to see is there any occurrence of x that is free? Yeah, so it was like an any check, basically. Yeah. So the second one, if you had an explicitly what the parentheses would, what the parentheses, the x, y, and the x. Exactly. So getting rid of these parentheses here means that the body of this abstraction is x, x, y, x, which would be x, y grouped together after applied first, and then that applied to x in the larger one. And that would make x not free. Correct. Exactly. Awesome. Any else? That's good. Okay. The free is really, really awesome. We're talking about a concept here. We're going to define it here, and then we're going to go back to it later because it's very cool and very important. Combinators. So a combinator is an expression that does not have any free variables. So if we think of this kind of like a function, it would be a function that defines, for first and no global variables. So it's kind of self-contained. It's also another way that they use to describe this called closed. It's a closed expression because everything you need to know about that function is right there. Pretty simple, right? Yes. Okay. So is this a combinator? The question asked here is, are there any free variables? Is this a combinator? Yes. Yes. Yep. Is this a combinator? Why not? Why is free. Good. Anybody heard the term combinator in another context? Close it? Yeah, I was kidding. Why? Why are you kidding? Where have you heard that term before? Yeah, so there's a famous, really famous actually incubator in Silicon Valley called Y Combinator. So the name comes from this, from combinator from Landococcalus, and that's actually one of the really cool things I want to get into is what is the Y Combinator. So we'll look at that later because it's super awesome, but that's why I wanted to find it here. So you may think, I was like a crazy theoretical term, but I guess you can say smart people think that it's cool and important too. Help me clarify. Yes. Could you do the parenthesis? Could I? Just point out where they are. So in this, yeah, in this expression, right? So you would have the body of this lambda x abstraction starts here and where does it end? The very end, right? Past this last x. And then this Y, the body of this abstraction starts here and where does it extend? Right before the last one. Yeah, exactly, right? Before the last one? Exactly. So this one would just be here, if you were going to put it, right? Same thing here. So the body would start after the, before this lambda, after this period, right in this body of this abstraction with z, where does it extend to? The end after z, exactly. And the same thing with this inner lambda x. Yeah? So inside of that x, y, z, which ones are your first x and y? What's the rule? Yeah, the less associated. So x and y are your first? Exactly, yep. All right. Cool, okay. So now I have to say what's the opposite of a free variable? Free variable? Not free, yes. If you want me to put it. What we're going to use is they use the term bound variable. So you got to think like this variable is bound to a specific abstraction. So it's very easy. If it's not free, it's a bound variable. Variables only have two. They're either bound or free. But the real question is what abstraction are they bound by? Right? So this would be, you kind of think of really one way to think about this is scoping, right? So what's the scope of this variable's usage? Right? So you kind of want to think about which, like a function, like we've been talking about with scoping rules, right? So we have variable usage. How do we trace that back to where that variable is defined? Here we don't have local variables. The only thing we have are function parameters. Right? Because we know how to then reference. Questions on bound variables? So we have some rules, even though it's actually pretty straightforward, right? So if it's not free, then it's bound. But the real question here is answering what abstraction binds that variable. So let's look. Okay. So if an occurrence of x is free in an expression e, then it's bound by lambda x in lambda x dot e. So if x is free in e, then what does that mean? Exactly. It's not part of any abstraction, right? And we know how to calculate if a variable is free. We can easily do it, right? So we say, hey, if we take that same expression, right, and we add a lambda x around it, put that as the body of an abstraction with a variable named x, now we know that x is now bound in e, is now bound by that lambda x expression. Right? So x was free. No abstraction was binding. So if we put an abstraction with the name x, then we know that x is bound by this abstraction. Okay. So now we're saying, basically, this rule says, hey, if we swap out, if we have an expression e, that's bound by a particular lambda x, which is inside e somewhere. And we say, if we take that same expression, and we just throw a lambda z around it, that doesn't change x's binding. Right? Pretty simple. So whatever abstraction you put on it, right, it's still going to refer to whatever, whatever it referred to. No, the really important thing is even if z is the same name as x, what concept is this of scoping that we've been talking about? Name? Equivalence? No. Reference? That's my reference. No. Scoping. Scoping rules. Dynamic scoping. Dynamic scoping. No. Close. I feel like we'll get there eventually. Yeah? Static scoping. Static scoping? It is a form of static scoping, but specifically what is this doing? Shadowing. Shadowing. Yeah, exactly. So basically this says, hey, if x is already bound to a particular abstraction, if you put another abstraction over it with the same name x, it still refers to that inner scoping, right? So just because there's an external x in a larger scope, the reference of x refers to the closest, innermost abstraction. So, for instance, in this case, right, so we have the statement lambda x, the body of that is lambda x, and the body of that is x. Right? So which lambda expression binds x? The second one. Yeah, right? We can see that these rules apply. Right? So if we got rid of the outer lambda x and just thought about this inner one as an expression, does this first rule hope does this first rule hold? Is x free in this expression? No. No, because it's all bound by an expression. It's not a free variable. So that means if we just add a lambda x, that doesn't change anything. Right? So you can think about this first rule kind of says the innermost expression is going to be what binds x. Right? Because that's when x is free. So if we look at this body in here, is x free here? Just this body, the inner one. Yeah. x is free in here. Right? Which means we put a lambda x in front of it. And that means this lambda x binds this x. And now that we have this binding, it doesn't matter what other things we add. The second rule just said it doesn't matter what you add outside or abstract, what more abstractions you add over that. That x is always going to be bound to this lambda expression. So this binding is just like scoping resolution. Right? So it's saying, hey, I have this free x and I don't know what it is. How do I find out? Well, you keep going up abstractions until you find the first lambda x that defines it. Yeah. Can you walk through reducing that expression? Not yet. Okay. We're not there. We have other things to learn first. Yes. So does that mean that any x, that x has to be defined somewhere as a lambda x in this recursive? Say that again? Does that mean that x has to have a lambda x somewhere in the recursive chain if you've got an x? No, no, no. Only for it to be bound, yes. Okay. So for an expression to be bound, there has to be some abstraction for a variable to be bound. There has to be some abstraction that has the same name as that variable. Otherwise it's free. So deciding if it's free or bound is very easy. We've all gone through. We can decide if it's free very easily. And then so if it's not free, then it must be bound. So the question is, how do you know which lambda abstraction finds it? That's just like static scoping rules, right? So you look at the abstraction one level out, and if that's not the same name, then you go two levels out, three levels out, and so you find and find what abstraction refers to. Okay, there's one more. Oh, wait. Somebody said one more. Okay, so there's one more rule which basically just says, hey, if you have, if x is bound by an abstraction, and in E1, then it doesn't matter if application doesn't change anything, right? It doesn't matter if you're applying an E2 or you're applying E1 to E2, that doesn't affect the binding scoping rules. Okay, exactly, because it's just about the body of an abstraction, right? So can a body of an abstraction span two applications? No. To me, really, this is almost superfluous because it's, it's only talking about the body of an abstraction, right? So the body of an abstraction can't span across two applications because it's an expression, right? So, yeah, so if you have a variable x that's bound, it doesn't matter if you, what happens on the applications, they don't affect each other in terms of binding. All right, let's look at some examples. Okay. So, which variable is binding to what? So, innermost parentheses do you want to go? So you want to go inside out? Okay. So, we have three variables here. So, what is this y bound to? So, let's actually say another one. So, we want to be kind of precise. Can't really be kind of precise, I guess. We want to show that we can apply these rules and be very precise, right? So we can say, okay, in this expression here, x, y, z, y, which variables are free? z, x, x, and y, right? If we just look at that inner expression, they're all free, so that matches the first criteria of that rule. And then we say, okay, now if we put a lambda meta variable, right, around that expression, whatever that meta variable is, is now bound in here. So what's the meta variable here? Y. Y. So now we know every instance of y here is bound to this meta variable, this abstraction, right? So here we have application, actually, here we have three applications, right? Yeah. So where, how far does this body of this lambda abstraction extend? Second, so last, or also, what's the seal? This one? Here. Yeah. So it extends here, right? So this is the body of this abstraction. So what variables are free in here? No. No, because it's bound to this abstraction, right? What variables are free here? X and Z. X and Z. Great. So we can say, okay, we know X and Z are free in this expression. If we put an abstraction around that expression, whatever that meta variable is, we know that free variable in there is now bound. So what's the meta variable here? X. So we can say every instance of X in here that is free is now bound to this X is this, this X is this, this X is this, right? The next part of free, everything that X bear with the Y, so that means it's very free, right? So then, let's look at these two, these two. So we can look at them in isolation. Remember, these are application, right? But we know that application doesn't affect the binding. So we can look and see, okay, let's look at this X is X free. Yes. Yes. So that means it's not bound, it's just a free variable. What about this Y? Free. It's free, yeah. So these occurrences of X and Y are free variables, right? Whereas these occurrences of X and Y are bound, each of them are bound to different abstractions. So if we were to color it, well, I don't want to color it, but that's not fair to people who are colored white. But, so I underlined every variable that was free and I bolded this abstraction, right? All of these X's. And I italicized all the Y's, all the variables that are bound to that abstraction. Right? So this would be something that could be asked on a test, right? So, did you say that even though an overall expression is not a combinator, it's a made-up of a combinator? Is an expression made up of expressions? Is it? Yeah. Yes. Yes. You can read yourself one way or the other. Yes? Then yeah. Then, exactly. So if the whole thing is a combinator, then maybe the inner thing is a combinator, right? But here, you have the innermost is this, which has a free variable, so it's not a combinator. Yes? See, in the most not, would that X be still, it wouldn't be bound to the most lambda X, right? Yeah. So what would happen if X is in the front? X would be bound to that X, and then the Y's would become This X? To the lambda X, to the one we changed. This X would be bound to here? No, the one right next to it. This X? So this one would be bound here, right? And not the outer lambda. So this is kind of the shadowing principle, right? So essentially the the inner abstractions lambda X shadows the outer lambda X. And then what happens to these Y's? They're free. Free. They become free variables, but no abstraction that takes them. Yeah, good question. What happens to it? So we don't know yet, but right now we can kind of think of we're defining the scoping rules of variables in our in our functions. So we need to define those if we need to know what because that affects how we actually compute the result things kind of. So, yeah. Yes? X would be free in that instance. So, you mean this was lambda X? Yeah. So the question is, actually when we first looked at this, right? We looked at the X, Y, Z, Y as an expression and we said, what are the free variables in here? What are the free variables? So I'm going to say again, what are the free variables in here? No, no, no. So we're not, remember, we don't even look at anything outside. We say, just the body, just this body expression, which variables are free? All of them. All of them, exactly. So it doesn't matter the abstraction that's outside of it, right? Until we want to say right, so even if this is a lambda X, the body inside the body, X is still free. Yeah, so you think you're just looking at that thing in isolation by like blocking out everything else with that expression. So you say, is X free there? The answer's yes and it doesn't matter what abstraction is outside of it. All right, let's look at another example. So what's bound to what and what variables are free? The right X is free? And what about, what about everything else? What is this X bound to? The first abstraction and this one here? What about this Y? The second abstraction. The second? And the Z? No. This one? Yeah. So that was X matching. X is bound to that X and that lambda expression, or that lambda abstraction. This Y is bound to this Y and the Z is bound to Z and this X is a free X. Free X. Okay. What about this? Z is free. Z is free? What is this X bound to? The inner one. The inner one? This one? No. This one? Second. This one? Yeah. I like it. Awesome. Okay, so this is bound to this. What about this X? The first one. Yeah, the first one. So we have these X's are bound together. These X's are bound, or this X is bound to this abstraction. This X is bound to this abstraction and Z is free. Okay. How do we tell two functions are equivalent in the same number of arguments? Same number of arguments? Same return type. Same return type? That's only about type equivalents, though. Does that mean the actual functions themselves are equivalent? What was it? Same body. Same body? Yeah. So maybe if they're like literally identically the same. Right? So that could be one way to determine functional, if two functions are equivalent. If they have the exact same bodies, then they shouldn't be the same. Yeah? If they do the same thing. If they do the same thing. What is that? What was that? So if they return the same values for all inputs and have the same stock steps, that would be... Yeah, so that would be one way. So that would be, I guess we're doing it at like two complete ends of the spectrum. Right? So one end would be, well, they're either exactly textually identical. Right? And the other end is more semantic, right? They are, or semantically equivalent, or they do the same thing given the same input for all inputs and have the same side effect. Can we do the first one? Yes. Yes, please. Yes, you can compare two things, right? Just tell me if they're exactly the same. Yes, you could do that. Can we do the other one? A lot more difficult. How much more difficult? You can compare the outputs of the two functions. How do you generate all possible inputs? So like, let's say they take in integers. So you're going to generate every single integer starting at zero and going out. How do you know when to stop? Maybe if you can reduce the expression to be equal to the same thing. You can reduce the expression to be equal to the same thing. In Landau-Kaijno's reduction is more of like an execution thing. So that would be, you still have to give it input, right? So you have to apply it to something, but you have to apply both functions to the same thing, make sure they have the same result. But it has to be for every single thing to apply it to, it's the same thing, yeah. Yeah, it's the same thing. The structure. It's the order to the matter. The structure of the equivalent. Like the equivalent of this domain, the structure of the equivalent. Yeah, so maybe they're structurally equivalent. I like that. I like that. If you compare the inputs out of the input, the input is a finite set. Because as long as the input is not a finite set, it seems to be a lot like when you're dealing with a Turing machine, it's pretty much both not decided what kind of thing. So let's say, let's think about it, right? So let's say we, even if it was five numbers, what happens if the function is looping forever on one of those five numbers? Or it seems, do we know if it's going to loop forever? Maybe that's just what it's doing, right? Do we not know if we need to keep it, have it keep executing for longer, right? So I think even that way, we still get into problems. I don't know off the top of my head if that's equivalent to the halting problem or not. The two functions have exactly the same output given the same input. I kind of intuitively think so, but I don't know. I don't know, I'll prove to that. So let's go back to this concept. So structural equivalent. So what does it mean for two functions to be structurally equivalent? Yeah, the same logic. What was that? Same logic. Same logic. Yeah, what was that one? Same operation. Same operations. What about those operations? It's going to go with same number, same number of variables. Yeah, same number of variables. Yeah, definitely. If you can have same parse trees for both functions. The same what? Parsh trees that we derived today. I didn't hear the word for it. Parsing trees. Ah, parsing trees. Ah, yeah, yeah. So that's their, have the same operators. Parsh tree would be they have the same operators kind of in the same order. That's kind of what I think of that. How do you, but could you make a program that has the same parse trees that are semantically different? Like how do you compare the parse trees? Because we compare them directly, right? If I say, think about assignment, right? If I have A is equal to A plus B, right? How do I compare that to, what if I have B is equal to C plus D? If I compare that textually, right? To make sure, okay, it's got the same parse tree and the same nodes with the same values. Then I'm basically doing textual representation, right? So how do I compare the trees to know that they're the same? Does that see if the logics are consistent? How do you do that? What was that? The binding. The binding? What do you mean? So right, one bad thing is, yeah, so we just compared the A plus B and B plus C, it depends on, I think to the lambda calculus, right? Where are those B's and C's bound to the same abstractions? Right? So yeah, let's take this a little bit forward, right? So are these two functions functionally equivalent? Yes. So maybe they pass our test that we created, or let's say we use our functionally equivalent as a structural equivalent. We'll give it a name in a second, but what's the difference between these two functions? Yeah, there's one who said, who came up with the thing, so we'll not use different letters, right? They have different variables, and specifically they have different variables with a specific name, with that are the bound, the variables in the abstraction here, right? So yeah, so we replace all the y's with x's, and then we have the same function, right? What about this? Are these the functions, or are they functional, slash structural, or are they equivalent? So we will not go ahead and fly. Yeah. We had some method to make the order of the variables the same, so you have kind of the same appearance of the x's and appearance of the y's. We kind of abstracted them up to the same value of the equivalent. Wait a second. So the x's and the y's appear it has the same format, they appear in kind of the same order, so if there's some way just to take the actual names out of it and make them take the names named by order of appearance or something, then they seem to be equivalent, because they're both variable names, so I might not be indicating them correctly. I'm trying to think. Does it? I'm going to ask you guys. No. No? Maybe. Let's go back to this one, actually. How would I look at it in a new light? I see it both ways. I'm not really sure. Okay, this one should be very easy, right? Yes. Equivalent? Awesome. Okay. Okay, so alpha, so what we're going to use, there's a term in lambda calculus called alpha equivalence which essentially defines the structural equivalence that we've been talking about. So the definition is the kind of intuitive way to think about it is alpha equivalence is when two variables or two functions vary only by the names of the bound variables, right, which kind of goes back to the, hey, let's just, if we replace, if we change the variable names, then we'll get the same function, right? So it's still functionally, it still does the same logic, but so does this match our ideal of having two functions equivalent if they produce the same output, given the same input? What was that? Not quite. Why? Yeah, exactly, right? All of you are proof of this, right? So you submit programming assignments that you can think of as functions that take in input and give output, right, so they're all doing the same, all of your programs depending on where you are, but let's say you get 100%, right? You're all doing the same thing. You're writing functions and giving the same input, producing the same output, but you're doing it in such a way that all the body of the function, everything is very different, right, depending on your logic. Otherwise we have problems, right, so it's a good proof. Okay, so we're going to use this term alpha equivalent, so expression one is an alpha equivalent to expression two, and this is what we mean by this, is that two functions vary but the problem is what we really want is we need a way to rename variables in the expression, right? So can we do just like a simple find of a place? Why? Because it might be bound to different bubbles. Right, because we have to respect the bound, the finding of the variable to the abstraction, right? So what about like this example? Can we rename x to foo? Can't we? What about y? Can we rename it to bar? Yeah. Can we rename y to x? No, good call, but no. There's too many things to keep in your head. So why can't we rename y to x given this original statement that we have here? Yeah. Yeah, so this x would then be bound to this x here, and now we have a different function with different logic, right? Can we rename x to z? What does that mean? What does that mean? Z is free, so how's that going to change our function? Yeah, it's now referencing a bound variable, right? So a variable that was free that's now bound, so now we've definitely changed the semantics of the function. Cool, so this is what we have to do is we have to, we're defining this renaming operator that's going to help us to rename, and so that way we can say that two things are practically equivalent, so we can rename all bound variables such that they're the same. Okay, this operation we're going to use, so we have we'll hint forward, so we're doing this very simple variable renaming, so part of the semantics here is we're going to represent this with e for some lambda expression, and then curly braces, y over x, so this means replace all occurrences of x with y. What are the types of x and y? We think of types. The important thing here about renaming, we're only renaming variables, so we can't, so x and y can't be arbitrary lambda expressions here in renaming, because we just want to rename one variable to another name. Okay, what are the three expression cases that we need to take care of? What was that? Something, yeah. Expression, expression, is that so? Expression ID? Yeah, lambda medivariable body, essentially, right? So we need to do that, so we need to handle all these cases. Okay, so the expression, so we're going to do this like we did before, right? We already do this. So if the expression is x, then what's the result of applying a renaming operation on this renaming operation on x? Why? Exactly, so if it's the thing we're looking for, if it's x, then change it to y. What if it's something else? What if it's z? I don't speak young. That would be z. Yeah, exactly. We don't change it, right? So if the expression is z or something, anything else that's not an x, any other ID that's not an x, and we say it stays the same, right? Because we're trying to replace what? x with? y, exactly. Okay, as far as to like x is on the bottom and y is on the top of this thing, I have no idea. This is just the convention. So, just got to learn it. Okay. What about, what do we do in the case of application? So we have expression 1 and expression 2. So this e is of the form expression 1 applied to expression 2, right? e1 space e2. So we want to apply this renaming operation to e1 and e2. Yeah, exactly. Super simple. We just want to apply it to e1 and apply it to e2. So now we get to the abstractions, right? So we have lambda so we have lambda ID expression. So what are probably, you maybe see there's kind of a similarity here between the cases that we're trying to define here. So what are some of the cases that we care about for the ID, the meta-variable of an abstraction? What was that? Say that again. You want to change the number? Yeah. There are 3 unbound and 3 free. True. So more looking at these cases, right? So this is saying like, hey, so the first case we have expression goes to an ID. So the two cases here are either the ID is X or the ID is not X. Right? These are these two cases. So in this third case, the next thing we have to deal with is the lambda abstraction, right? So we have to somehow propagate this renaming operation into the body. What are the two cases we care about? X is free or X is found? X is free. Kind of. Kind of. Actually, okay, let's look at this. So, yeah, okay. So, if it's a lambda expression, right, and the meta-variable is X, then so, okay, I should set back a little bit. This renaming operation is very simple, so it just does renaming. So, we're basically replace every occurrence of X with Y. We're going to do other things on top of it that are smarter than taking these things into account. So basically it says hey, if the meta-variable is X, then change that to Y and apply the renaming operation to the body. So what if the meta-variable is not X, if it's something else? What is it? Don't do anything. Don't do anything. Well, except pass it through, right? Exactly. So if we covered all the cases, can expression be in any other form? So what are the three forms, right? So we have ID, we have application, and we have abstraction, right? So here we have two cases for ID, one where X, the ID is X, and one where the ID is not X. And here we have the other case, we have two cases, one where the meta-variable is X and one where the meta-variable is not X. So with those, with the five cases, I might put it down quickly. For those five cases, right? Those, we know that those cover all of our cases here. Pretty easy, right? Change of recurrence X to Y. Okay, let's look at some examples. Let's look at this. So we want to apply lambda X dot X, first thing, is this expression a combinator? Yes. Why? No free variables. No free variables, exactly. So what are we replacing? Are we replacing X with foo? X with foo, exactly. So we apply this here, what's the first step? What are we doing? What are we changing? Yes, we're changing this X here to be foo. And then we're doing the body of that, we're going to pass this renaming operation. And then we're going to apply this renaming operation to the expression X. And what's that going to change? X to foo. So we renamed X to foo in this expression. Okay, this is a little hard work. This is the one we've already seen, so it's not so great. I mean, it's crazy, but it's not so crazy, right? Just wait. Okay, so here we're changing every bar to X. Every X to bar, exactly. Okay, so what's the outer level, what type of expression is that? The outer most, the top most expression? Application. Yeah, exactly. So it's application. So we're going to apply, basically we're going to pass bar X to eat everything in the application. So I've done that to this one, this one and this one, right? So then it's going to, we can apply it wherever we want to first. Let's say first we apply it to Y, what happens to Y? Nothing. Nothing. And then we're going to apply it to X. What happens to X? Changes to bar. And then we apply this to this abstraction, so it's going to change here. So X is going to get changed to bar. And then we're going to apply this to an application which we apply it to each here and here. Yeah, I've already applied it to this X and this X and then we apply it to the inner one. It doesn't change the Y and then so we apply it to the inner one, this bar X. So it's going to end up changing this X to bar and here we replace all X's with bars. Pretty simple, right? So this replacement doesn't, yeah. If we're taking the two parentheses on the outside out so that I mean it subtly changes it Yes. It frees the X on the end so there would be no replacement on that X just to clarify. On which X? This X? There's two other parentheses because it would no longer be found. Is this X found? No, it's free. It is free. This redaining operation just changes all the names. Just changes everything. So we're defining this simple operator and then we're going to do things with it that are better, basically. Yeah, there's a hand. I can't do it. Why don't we do a what? Ah, essentially that's what we're doing, right? But you have to define it, right? It has to be defined how to do that for every single and how to transform every possible expression. So that's why we're defining all these things very precisely so we can see exactly what this operator means and what it does. Alright, so now we go to alpha equivalent. Okay. So what we're going to find is that two expressions are alpha equivalent if for all expressions in E, so, okay. So for all expressions in E, any expressions you can think of, for all E, for all variables Y that do not occur in E, if we take E and it's abstracted over X, this is alpha equivalent to lambda Y expression replacing X with Y. So basically this just does exactly what we thought and what we wanted to do is, hey, if we replace the bound variable and we change it to something else and change that inside then those two things are alpha equivalent. So it's alpha Y dot Y, oops, I should have added the alpha there, alpha equivalent to lambda X dot X. Yes, Y. Right, so we can take, so E here is this expression Y and if we take Y so this would be lambda Y dot Y and we can make a new expression by substituting Y with X, then we get an equivalent expression. So basically this statement says, hey, if you Y in this expression, if you can take any abstraction over any variable as long as we replace that Y with whatever you want, those are alpha equivalent. What about this? Ah, so here E is the body of the expression, yes, so this defines alpha equivalence of functions, right, because we're abstractions, because we don't care if two applications are, you know, we don't care if two IDs are a function equivalent, right, we care about, because that's what we're talking about, right, we're talking about how do we define functional equivalence. So yeah, here this defines that an abstraction over a variable E. If we change that abstraction variable to be whatever we want, then that's alpha equivalent to the right-hand side. No, I know. Yeah, so I think they're a really good point. So this would actually definitely be no because this is an application, right? E here is like this whole thing. Is this whole thing in the form lambda something dot E? No, exactly, yeah. So that would definitely not make these function equivalent. Let's look, what if we get rid of the X, Y, and the Y, X, and just compare these inner functions, just that we'll know why. Yeah. Right, because we're only replacing bound variables, exactly. So this does go to answer our convince myself. This does go to answer our earlier question, right? So Z here, is Z bound or free? Free. Free, right? So this says, hey, you can change any bound variable to point to be a different name, right? But Z is not bound here so we can't change that to be another name so these expressions are not alpha equivalent. It makes sense, right? And that references a global variable and you have another function that references a global variable with different name. Now you can't really tell, these functions are not necessarily the same because depending on the context that they're ran in could have different results, right? But if they at least reference the same global variable, then you could say they're functionally equivalent because they have the same operations and they just vary based on the parameter name. Can you go through some examples? Okay. So we have to do one more thing, right? Okay, so renaming gets us almost all the way there. We can change things but we already saw well, changing things, changing names, right? Just willy nilly. So here, this we're only ever changing bound variables, right? So that's fine because we're never going to accidentally change a free variable. Nothing like that, right? We're only ever changing bound variable names. So okay. So we need something else because we saw that there's cases where you want to change a name but maybe that's going to mess up the resulting function, right? So what we're going to define as a new operator called substitution and this is going to be everything we're going to need on Monday. We're going to go through the actual execution semantics or the reductions. But we first have to define this operator. It's called substitution. So what was the end goal example that we were talking about that we wanted to be able to reduce or compute from lambda calculus? They look exactly the same. So yes. So what we want to do, right? Our goal that we're taking when we really want to go to is we want to take, be able to reduce or compute really a function sorry, not a function, an application. So here we have lambda x dot plus x1, right? This is the example I used. And if we apply that to 2, right? Really what we're doing is this when we reduce this we want to, oh sorry this is supposed to be an arrow. We've got a little mess up on the lines here. What we're doing is really replacing all the x's with the parameter 2, right? So that's what we want here which is plus 1, 2. So really what we want to do is replace x with expression 2. But can we use renaming? We just renamed all x's to 2's? No. Like in this simple example, yes. We've already seen cases where renaming completely changes the function meaning. So we definitely don't want to just do renaming. So we need another operator called substitution which is what we're going to use to replace a variable a variable by an expression. So the form of this is going to be different. So this is the way we can keep renaming and substitution distinct is that here we have an expression and we're going to say replace the variable x with n. So the difference here is n is now a lambda expression. It can be any arbitrary lambda expression or before what was the what could we use to replace a renaming? Just id's, right? Exactly. So here the type is id replaced with an e, an expression. So then you can, once we have this once we're able to replace a variable safely with an expression then we can use that to reduce this application by replacing all of the x's with 2's and now we've done some computation as we'll see. You'll have to trust me at least right now that actually is computation but this is where we're going and this is why we need to define this new operator. Questions on the substitution operator? It seems pretty simple. So this is kind of where we're going. We want to say hey if we have the expression plus x1, we want to replace x with 2 what do we do? Or we want to, sorry, substitute substitute x for 2 what do we do? Intuitively without thinking about it too much. Is that x to be 2? Exactly. We'll just replace x with 2. Bam. So we want to get plus 2, 1. What about in this case? So here I have an abstraction of lambda dot plus x1 and I want to replace x with 2. Remember this can be an arbitrary expression right? Definitely can't replace the first one, why? Because following a lambda has to be an id can't replace, it can't be the first one. Exactly. So you can't, definitely can't replace this x because it has to be an id from the syntax that we know. So you just tap 2 on the backside What was that? Like you would apply 2 to this function. Apply 2 to this function. We'll see exactly how this works but here we want to think about substituting x with 2. What's the difference between this x here and this x here? Yeah, bound. This x is bound and this x is free. Right? So we're going to replace a free x with whatever expression we want. But here we actually, there's nothing to substitute because x is already bound. So we actually can't go into that expression to reduce, to replace that x with something arbitrary. So you only can do substitution on free variables? Yes. We'll get to that. We're trying to build up some intuition so when we look at the rules they kind of make sense. They're not just arbitrarily handed down. Okay, let's look at something that's slightly more complicated. So here I'm actually using instead of 2 here I'm using so what we want to replace we want to replace all the terms of y with the expression lambda z dot xz and our expression that we're replacing is lambda x dot yx. So so does the first thing hold? Can I actually do this replacement? Yes. So if I replace this y with lambda z dot xz is that okay? No, because it finds the x inside that function. Exactly. Everybody see that? So if we replace this in here it's like this right? Where is this x bound to now? Yeah, the first line though. Where is this x bound here? It's not bound. It's a free variable exactly. So is this terrible? Does this mean that we can't apply this? Or can't we do this substitution? Rename what? Yeah, so the way it's done is so one thing we can do, well can we rename the free variable x? Yes. Yes? Would that be an equivalent substitution? I'm checking ahead to know why. We can replace what? Bound variables. Right, we can replace bound variables without changing the semantics. But if we replace this x this is a free x. It may refer to something important. So if we change that to some other variable now how do we know how to do that? What about this x? Do we change this x? Yes. So we know how to do that. We saw the renaming operator. We can change this expression to something that's also equivalent by changing the x and we can change it to y. No, because that messes things up. What can we change it to? Something not here. Yeah, exactly. We can create a new variable because it doesn't matter as long as inside this body all of those x's are changed to now w's. So we can do that. So here this actually allows the substitution operator to operate correctly. So we'll stop here and maybe I'll assume that you all know this before we go on. Yeah, so we'll come back to you on Monday.