[MUSIC] I want to wrap up our study of macros by just showing you some more sophisticated examples that expose some new features and are just a little longer and put together some things we've seen. So we'll do three examples. One will be a sort of for loop, I've put it in blue because this is most similar to a homework problem I like to assign. The purpose of this is to show a macro that takes multiple arguments, some of which we want to reevaluate and some of which we don't. Then I'll show you a special version of let we defined that can let you take a few different possibilities with fewer parentheses. And that'll show how you can have a macro with multiple cases. Then I'll show you another macro that not just has multiple cases, but is even defined recursively. So it'll be a recursive macro that ends up calling itself. And that will be a full re-implementation of let* just in terms of let. It's a fairly standard example for this sort of material. Okay, so here is this first for example. And these things are sometimes a little hard to read, so how about first I just show you how it's used? I could say something like (for 7 to 11 do (print "hi")) and it will print five times because 11 minus 7 is 5. Of course, I could have defined, I can have arbitrary expressions in those positions. Suppose I have a function f that prints, let me do the begin prints A and then returns x and then I have another function g that prints B and then returns x. And how about one more, a function h that prints C and returns x. And now what's kind of interesting to me is that I say (for (f 7) to (g y) do h, I'm sorry (g 11) do (h 9)). And it prints A once, B once, and C five times. This is probably what a user of your for loop would want. It would like to see these things evaluate in this order. And to get this right, we need to be a little careful on how we define our macro. So here we have our for. It clearly has two extra syntactic rules, to and do. Those are not expressions, so we wrote those. When we have something like have for lo to hi do body, we want to have this expansion. So we use our idea of the let expression to evaluate first lo, then hi, in that order. We will put the results in l and h so that we do not evaluate lo and hi again. But then we do want to evaluate body one time for hi minus lo, for every number between hi and lo. And so here I've defined a little recursive helper function loop to do that, and you'll notice, you can follow the logic yourself. But right here, I paste in, if you will, body and so that will be there in the body of the lambda. So every time this lambda gets called, body will execute. And it's inside a recursive loop here where it gets called the right number of times. So that's a nice example of controlling the order things that are evaluated and how many times they're evaluated. Let me show you one other example of it, by the way. Which is if I flip around so the beginning is larger than the end, then it never prints C at all, which is also the behavior that I would want. So that's good, all right. Let's do another example. Here is a version called let2, this is kind of interesting. Let me again start by showing you how it works. I could say let2 and I can define up to two variables. So when I use let I need these extra parentheses y 2 and then a body like +( x y). But let2 takes out these parentheses and I just write it like that, but I have to call it let2, there we go. And that does the right thing, it produces 3. It also allows too few things. So that does the right thing except that you can't use the variable you deleted. And it even allow zero things and then you could have a constant in here like 2 and 2. Okay, so that's the idea. Let's see how this one works. The key thing I'm introducing here is that you can have multiple cases in your macro. So, I'm defining let2, all right? No extra syntax rules. The first case is if you see let2 then parenthesis, parenthesis then body just replace that with body. That's not the end of my macro. The second case says if you have let2, one thing, another thing, and then a body, replace that with a let that has one binding. So basically just put in some extra parentheses. Everything will work. And the third case, which is right here, is if you have four things in parentheses and then a body, then do this nested let, where you have (let ([var1 val1]) then (let ([var2 val2]) and then body. Of course, I didn't have to do this in this nested way, you can expand it however you want. But this does the right semantics and nobody will be able to tell. So that's how it works. What about if you use it incorrectly? This is actually kind of interesting. Let's say I give it too many arguments, something that is has no case for, x and y, I don't even have to use z. This just simply does not match any of the three cases. Then I get an error message it says, let2 bad syntax. It says it doesn't match the macro, it's a bad syntax. And similarly, if I had three things instead of four, I would get the same error message. Now, here's the final one I want to show you. This is actually kind of interesting. Suppose I write this. That actually does match the macro, it matches this third case. This third case says let2, followed by four expressions, which I have, 3, x, 4, and y, followed by a body. But, after I do the expansion, I'm going to get a let expression that's not syntactically well formed, because I'm going to have a number for var1, and a number for var2. So, what happens? I get a syntax error message, but it's a different message. It's actually telling me this is a bad let, right? And the problem is this 3 where it was expecting an identifier. So this is always a problem when you use macros. Depending on how you define them, you can end up having error messages reported to your user in terms of the expansion instead of in terms of the macro. And that is just a difficult thing about using macros, where I could have some support for improving error messages. But I'm going to leave that subject there where we have it. Let me show you one final example. This was this recursive macro. Suppose Racket did not have let*. It just didn't have it, it had let but it didn't have let*, and you really wanted a let*, you could define your own because Racket supports recursive macros. So I'm defining a macro here called my-let*, this can have two cases. Here's one case, here's the other. The first case says if you my-let* then the empty list of bindings and then a body, just like we do with let2, replace that with just the body. Otherwise, we have some special syntax for doing this kind of recursive thing. Do a my-let* with this pattern. This says you have a first parenthesis and then a var0 and then a val0. And then after this next one you have this special thing, dot dot dot. This is actually a special thing in Racket macros. This basically says well, you can have one or more of the previous things and we can refer to those all together and then a body. And so that is the pattern we're matching and then the way the macro expands is into this. So, it's a let with var0, val0 and then that let's body is this recursive call to my-let*. Where I pass to my-let* the syntax that is all the other bindings, including this dot, dot, dot, and then the body. I just wanted to show you that I don't claim that from that you'd be able to write your own recursive macros. You should probably consult the reference to see how to do it, but I wanted to show it was possible. And it even begs the question of well, what if you wrote an infinite loop in your macro expansion? Well, that would be a bug. And before the program ever started running, it would try to generate an infinitely large program, and that would eventually crash before anything ever ran. When you write programs, you can have bugs, sometimes bugs can do unfortunate things, when you have a powerful feature like a recursive macro you need to use it appropriately. And we've seen how, thanks to having our recursive macro, you can do something as fancy as let*, even if the underlying language did not give it to you. And that, with that last bit of fanciness, concludes our study of Racket's macro system.