 I was hoping to clarify the restrictions on recursion during this project. For example, we're supposed to write the initial program parser, and I was hoping to still be able to do two separate parsed functions. Ah, okay. So the recursion, okay, here's what it is. You can't just print it out. You can do recursion absolutely to the parser, right? Just like on Project 5, you are doing a recursive parser, right? Because you're parsing the main body, and then when you get to, like, a while statement, you have to call pars body again to parse that body, and if that has, you know, any while statement, you can call pars body actually, right? So your parser is definitely recursive. It's you can't make the compiler back-end recursive, right? Because you're trying to support these expressions, so you can't change the compiler back-end to be recursive. But you can't tell the compiler back-end to just, oh, recursively execute these things. I thought we weren't allowed to do that at all. Not just for that bonus project. Yeah, no, no. For the bonus project, you actually need to, you may need to change the back-end, which is fine, but you can't change it. You should make it be recursive or to call other functions. Oh, okay. I was really confused on how to do it back-end. No, no, no, that's a good clarification. I'll try to send something out in the mail. Okay, it's, when I saw the emails and read the project, I thought we just weren't allowed to use any recursions. I was like, how am I supposed to do this iteratively? No, no, you don't want to do it like that. Use recursion from our side. Other questions? Project homework four or bonus project five questions? Okay. I'm just thinking about it like this. So, part of understanding the types, what they are, the program means that you know how to call that function because you can create a function of that type or an array of that type and you can pass it in and you can try to get the channel and get what you're using to pass this type of language. So, the question you asked yourself is, can you create a type, like a variable with a type or a function with a type if it's written on the mail? So, for instance, right? So, let's say, let's do a super simple example of this thing. No. Yeah, why it takes like an hour to do the same thing. Okay. Let's say we have some function foo, right? That takes in an a and b. Or what's the define? I have a double define. I think it's fine. Okay. Let's just say a plus b. The type of foo, right? We don't know, we have no constraints on the type of foo. But we know that the type of foo has to be a function that takes in, let's say, t1. And a t1. And returns a t1. We don't know what those types are. They could be any type, but they all have to be the same. Which means, if you want to call function foo with, let's say, variables d and e. So, if I say d is an int. And e is like a string. This will cause problems. This cannot happen. But if I wrote it like this, it was an int. Can I do that? And then, do I know what the return of this function call is going to be? An int. Exactly. So, can you, let's think of some other way. Let's think about type errors in a different way. So, let's say I have a new foo again because I'm thinking of coming up with names. Let's say we have return, let's say, let's return a plus 1, plus b plus l. So, we tried to type check this. You get a is an int and b is a string. But you get that a and b are the same. So, b has to be a string and an integer at the same time. So, the problem with why this is a type error is because if I wanted to call function foo with some new variables d and e, right, what are the types that I give these variables? Like a variable cannot be both an integer and a string. Like there's no possible type I can write here for what these types of d and e are to allow this to occur. So, if I have, let's say you have function foo that has two parameters, int and int. We are trying to write a function for the same parameter as int ago. Could you use those functions any more? Could you use them interchangeably? Right, so kind of, it's almost, it's actually similar to thinking about classes, right? It's like when I, if I expected a bar, could I pass a pass? Yes, because I know everywhere that baz is used, it's been called with two integer parameters and it returns an int. Which means I can use a baz there instead. Obviously the semantics will be different, but the types will be fine. That would mean, well, okay, so, okay, let's answer some questions kind of in turn. So, could you write a function like this? Probably shouldn't have a little bit of water work right now. Right, so now a bar is a function that takes in as its first parameter and int integer. As its second parameter it takes in a function that takes in two parameters and returns one, two integers and returns an integer. And it bar itself returns an integer. So the question is, is this a valid type? Yes. Shut up already. I don't know, I mean, I'm not going to help you. Yeah, I'm not going to help you. Let's, how should you think about it? How should you reason about it? Reason one way or the other? Are we allowed to say it throws an air? If I gave you something like this, right, what would you say? I would probably return the n to be like that. Like this? This can't possibly be the case, right? Just like we're doing project four. A variable can't be a string and an integer at the same time. I don't know what the language is doing. It could be something funky. This is exactly the type system it's trying to prevent you from doing it, right? So you'd say, or like, let's say we, another example, right, let's say we have foo, right, and then we, with foo, we, let's forget that. So we take an a, right, can we say, if a, right, return a, else return zero. So here, this means a must be a Boolean. This means that a must be an integer. In our language, you cannot, you can't be an integer in a Boolean at the same time. So what would you say if I acted as type? Check this. Type error. And you'd probably explain why, right? It's val and c code, though. Yeah, I know. That's, that's because the type system of c is old and pretty much, it's a little bit more flexible. Yeah, it allows you to, it will allow implicit conversions between types. And it actually specifically allows, actually there is no Boolean in c, right? It's old. It's a big problem. Yeah. It's just incredible. So for all the theoretical stuff in this class, we just don't go with c, but every time it's code base, we think of c, sometimes x, it just depends. Yes, and I probably, I won't ever test those weird c corner cases, right? Like, those are the things we're interested in. We're just interested in the execution semantics of c. So this, I mean, for this, we're going to do the Pindley-Millner, what we discussed in class, right? That's kind of the language that we built up. So with the definition from what I'm seeing on one of the problems, I can write code that would work with it, and it would just be stuck in an infinite loop. Because you write code that would work with it. Yes, it would be in an infinite loop, but it would do nothing in the end. But it would technically, you could just put it in terms of my return condition for, I mean, exit condition. That's what I'm talking about. Say that again? It doesn't matter if it goes on it, if it goes through the medium, because it's on it. Types, yes. Well, I don't even care about the types, right? So that's the only way to think about it, right? Here, I can say there's clearly a type error, right? I'm using, I said it's a bool. This condition says it's a bool. If this says it has to be an integer, I can't unify those types, right? I'm using the bool in an integer, right? I mean, another way to think about it, right? I need, you really don't need to tell me what the types of my function are. If you can't tell me that, then the function doesn't type check, right? I mean, you can figure out the type still. It would just, in the end, it would be an infinite loop. You can't resolve it. But how could you write, how could you call that function? I think it's the order of... Can you call that function? What do you write in here in case of calling that function? Because each type has to be finite when it's in a variable, right? I mean, BD at runtime has to have a finite type. Yeah. Right? I need to be either an array of ints. I can't be an array of arrays of arrays of arrays, right? This doesn't make sense. Can I do a function, can I define a function and then put that in or no? Like, so I said... That would be another thing, right? Is another way to do this would be like, these are functions that it takes in? Yeah. Write one of those functions. Write a function so that it has that type that you declared for this parameter of foo. We can add a new variable. In the healthy mill... Are we assuming there are no local variables or can there be local variables in that function? You're... I mean, it's whatever the function says. We didn't introduce local variables, but they would be the same. You would just declare, like, a variable. It wouldn't have a type. You'd just say, like, var a, and then based on the usage of a and a function, you would infer the type of a. You have to keep all the constraints, too, that you have, right? Didn't we say that in the movie mill there that we could do reals also? Yes. So can we not do a real plus that one? Correct. Yes. So we could not do, like, 2.0 to 1. Okay. If you think about it, right, I mean, the compiler doesn't do this either, right? It doesn't add because the way it represents floats versus integers does not allow you to just add them together, right? The compiler actually has to know, hey, this is a float, even though they're both 32 bits, right? This is a float, which means it's an IEEE floating point format, which means that the compiler, actually, the C compiler is smart enough, quote-quote smart enough, right, to automatically transform this float into an integer and then add those integers together. So basically it knows that it can do that and it knows how to transform it. But you could do this, right? You could write a function that takes in a float and returns an integer, right? Like, 2 int, right? And if you do this, everything works fine. Right, the type system here. Do you have more specific instructions? Yes. You are feeding, yeah, because this knowledge, right, of how to transform floats to ints must exist somewhere. It just happens to be in C and exists in the compiler. So, like, actually programming languages that do Hindley-Miller type inference, they vary based on what they allow you to do. So, like, Scala, you can actually define functions and say, hey, this function can be used always to transform floats to ints. And then the type system knows that, so then when it sees this call here, is there a function that will get me from floats to ints? And it will automatically use that. But it makes the code a little bit weird to read. But what do they kind of, like, change the second int to flow instead? C? Yeah, I would. I guess I just said that. So it's going to return that a float? No, no, no. Hindley-Miller will not, like, by default, will not do any of that. It will just say this. The type system does not allow this. And so, fail. Okay. Any other four questions? Sure, we'll do that too. Sure. Good question. You haven't had my jam with me. I missed you. You have to go to the TA. So, for the Ape State Mania 105, I assume that when I do a true branch, I just kind of have to read whatever is in the parentheses and then I will really kind of, like, whatever is followed at right parentheses in the failed branch. And then I look, and then to be able to kind of, I say to do, like, a true statement and then the failed statement, I would loop the I would loop the true statement to the end and then link it to the failed branch. Isn't that right? Then you get to the false branch? What do you mean by that? So just kind of, like... You're talking about, like, it's statement or false? It's statement. It's statement? Yeah, so it's kind of like, after you do the true branch, and you will still go, go into execute the failed branch, right? Right, okay, so in our language, right, and if, right... Yeah, cause the failed branch is at whatever level after that. But there is no false branch. I mean, there is no explicit false branch here. So the false branch is basically, right, the next instruction. Yeah, actually, the next instruction. Exactly. So when you call parse body, right, so you should be, this is a body. So you should call parse body here to parse this, so that way everything will happen and you can deal with recursive ifs, right? So yeah, so what you're going to want to do, right, is make an if statement, right, make an if statement that's, just like you said, right, true branch is this body. Yeah, and I'll read a body, and after that I'll read a statement. Which is statement lists, right? And then the false branch, right, we said we want to actually create this no-op statement. Yeah. Right, and so we're going to put this false branch here, but let's look at this diagram we have here, right? And then there's going to be, so this returns, right, we're going to return essentially a pointer to this if statement. And then our parse statement lists is going to create, like, I don't know, the next assigned statement or whatever, right? And it's going to set this one's next, don't do this assigned statement, right? But look at, well, this picture we just drawn, right? No, we also link the true branch to the next. Exactly, that's the key, yes. We need the true branch, right? We need it when we get the body. The body only parses what's inside here, so the last statement there has no next pointer. Yeah, I know. It's exactly what I do, but however, it's proven I'm dead. After I access my true branch, I don't know why it doesn't go to the next assigned statement, like, it doesn't sound as any difficulty to, you know, link one link list to the end of another link list. I guess nothing difficult about it, but in my case, I don't know. Is it actually the same NOP statement? So you got to look and see is the last statement list here, or statement node, in your body with the true branch. Does it point to the same NOP statement that you're using here? It should. You should check that. Like, one problem would be if you make a new NOP statement, you mount up a new NOP statement, right? They're going to go to different places. So you need the false branch to go to the same place. You need the true branch to go to the same place. Yeah, this thing is like, I define my new statement kind of like, outside my true branch, so it's kind of like, I call the get body method kind of like, get whatever is in the true branch. And then, so after that function returns, I create a new statement, and then I will set the new statement to the next to call what I want to call a stimulus, to kind of like get what it was after that. And then I will have the false statement pass to the new, and also have the end of the true branch pass to the new. You shouldn't be calling, right? Your if statement should only pass an if statement. It should not be passing what comes after it. I mean, kind of like, whatever after this, kind of like. But you, but the if, parse if should not parse what comes after it, right? Yeah. Parsing if should only parse this right here. It should only parse these, it should not call parse statement list to parse everything that comes afterwards. No. No. I'm going to just kind of like, link my... Exactly. The problem is this, no ops, exactly, right? Just like you're doing it normally, right? We're actually in a statement node, statement node, and we put in the pseudo code that the statement node, right, this has a pointer to this if statement. And we have its next be this no op, right? That's what we said in the pseudo code we should do. Because when you call parse statement, it's going to return this. But unlike normal statements, right? Normal statements, we want to set the next of a statement equal to the next of one of the statement lists. I think it's still exactly what I did. It's like, I have a... I think I called my new in the kind of like, the statement list kind of, so I would... So I didn't set the... I didn't call the list in the... in the if statement, instead I kind of like, I left it outside, so it would kind of, I still have a structure like that. But will it? I mean, this is what you have to verify. Like, you have to verify that this actually has this structure. The key is this link here, right? The parse statement, when it sees that it got an if statement back, it needs to set not the next equal to the next instruction, right? Because honestly, this pointer doesn't matter at all, this next, right? Because we're going to go in the if statement, right? It's going to go here. What we want to set is the next, next to point to the next instruction. I would check with that. Yeah, check the pseudo code. If you try to match up the pseudo code with your code, you can hopefully figure out what's going wrong. And then you need to like, debug your code or go through it by hand and draw this structure and be like, okay, what exactly is happening at all these points? And the other key is you can't have, you want to make sure that your if condition, your if parse if statement, does not parse anything afterwards. You got it. Okay, just, just, I, for you and everyone else. But I have to go in class. Maybe like one question. Okay, yeah. Look at my diagram for the switch statement here. So we start with like a statement node when you enter it. And then it's going to be, it's going to be representing the if switch. So then you're going to have two branches for that. If it can be true branch falls or false branch falls. So if that if statement falls, the false branch is going to parse the body, come down through whatever statements are in it. And the last thing you're going to point that to is going to be a go to to the no op statement off the next of your original statement node. But if it was a true, then it links that true statement, true branch of that if statement to a new statement node here, which would follow the false branch go here. And at the very end, if it doesn't find any matches and there's no default, it would have, well it's be a go to statement says not, but it should be go to, which would read all the way over down to here. So that would be. Yeah, that should work. Okay. Because you already have a logic of the if statement to do this mapping, right? So when it parses, when you return that, it will set the next, next to be whatever the next instruction is. And so we'll properly set that up. I'll call him. Cool. Thank you. Just do it. You have to go, we're going to walk and talk a little bit. Can I ask a real quick question? Like one minute. Okay. So, can we define a function that takes a, can I do this? Just that. I came up with a valid code for this, but that's not important. Can I do that? What does the function look like for that? What is that? So, the second line? Yeah, basically the two of those together. The two of those together. So f is what? F is a function. So what's the type of f though? Type of f is what? A function that takes in what? Takes in another type f. And returns a billion? Yes. Cool. So write a function that does this. Should zoom. Okay. Wait. But that doesn't, it takes in, d could be that type. Is it that type? Because d doesn't return a Boolean. I mean, for all we know it does, I can make a d function that returns a Boolean, but the point is it doesn't need to even be called. You can still return true or false. True, but d, we need to know the type of d, right? And d has to be a function to be able to be passed into there. I mean, I do use d up here, and I use it in the same way. This would be a valid thing according to our language. So these are valid, right? But this function a is, has the type a where it takes in anything, t1 and returns a Boolean. Yeah. Right? But when you pass it in here, it can't be just anything. It needs to be a function that takes in an f and returns a true, right? So like here, your function c, right? Yeah. What's t1 and t2? Let's say Booleans or something. Yeah, they're just type t, because c can be anything from the definition. Right. So how would you call function c? Like what do you pass in as d here? Like you may, maybe you can define these functions and the way you've defined them, you're right. The way you've defined them has the type. So like the type of a is t1 returns a Boolean. Right? Yeah. But what is, how do you pass in like that's actually passing the function or we're just passing in the type? It has to be a function, right? This tells you that this has to be a function. Right? So can you pass your a into, let's just say like a, into this, call this f with it. Right? So if we have a, the type of a is this, the type of f is this. Right? Can I actually call that? Like I need to know what this type t1 is. Right? So like to use this, what does this mean about the type of t1? That it has to be a function that returns a Boolean also. Well it, it means that it could be anything. Like, this means there can be anything but using it here means that it has to be what? Right? So like up here when I had, right, like here, right, when I call foo here, this function foo, right, it returns a t1, t1 returns a t1. When I call it here with d and e as both integers, right, integers. It means that t1 has to be an integer for this instance, which is how I know that it returns a t1. Similarly, right, the same thing happens here. When I try to call this function f with a, it has to, what is the constraint of type one have to be for this to hold? I don't think there is a constraint since it's not, it doesn't end up being used. I mean, we want to know if it's correct because maybe there's other constraints like it doesn't matter that it's used or not used, right? It'd be like the most generic possible, whatever top level that would be. But we want the most specific, right, we want the most specific type, right. So normally, if we pass this in here, right, we say, okay, this is my parameter that I'm passing in. This is the parameter of the thing that I'm passing in, right. So, but what is Tf? That, so can we not define types like that? Right, but what is Tf? Well, Tf is also, so for this to be correct, right, this would also have to be T1 goes to Boolean, goes to Boolean, right. But this T1 is also a Tf. So it would also need to be Tf, T1 goes to Boolean. So am I ever going to stop? No. So would this be a valid type that I could write out? Not manually. Not manually, even if the computer did this, how long is it going to go? It will go infinitely. Infinitely, all right, I've got to go, yeah, so if you can't write that type down, you can't call that function.