[MUSIC] So now, without further a do, let's learn how to define our own Macros in Racket. There's a lot of syntax for defining other syntax. But we can just go through it line by line. And we'll do the 3 examples that. We used, a couple segments ago when introducing the idea of macros. So the first one I'm going to define, is my own version of if. Where users will be able to write my-if, some expression like foo. then bar else baz. And of course, the foo bar and baz can be any expression, arbitrarily deep as many parentheses as you want. And that will get expanded into if e foo bar baz, with the same expressions being expanded. So how do we tell racket that we want to have this macro? We start with the define syntax keyword. So it's not define, it's define syntax, because we're not defining a variable or a function, we're defining something different. The name of your macro, so my if. Then this other keyword, syntax rules. So we're going to give some rules for the syntax. That's in parentheses, like here. Okay? Then, a list of the other keywords in this macro besides my if. So, in this case, it's then and else. And you have to tell it this, because it doesn't know that we want then and else to be special words. Whereas, the other things, we want to be any arbitrary expression. So, now we have a list of cases. We can use square brackets for this to delineate it. We could have second one here and then a third one, but in this case we always just want to expand the same way no matter how my if is used. So we're just going to have one, that's fairly common, so we just have one thing in this list but you need those square parentheses. And now what we say, if you see something like this. Expand it like this. So what does it mean to see something like this? It says, if you see something in parentheses that starts with my if. Then has anything you want, call it e1. And then the word then. This and this. We know that we mean this particular word, not in anything you want. Because then is up in this list then anything you want called e2 then exactly else cause that's up in this list and then an e3 then it matches and the way to transform it is into this if e1, e2, e3 where kind of line pattern matching expect we're defining a macro here this E1 is whatever expression was here this e2 is whatever expression was here and this e3 is whatever expression was here. So this really does work. Right? If I say my if of true. And plus 3, 4 and 72, I'll get back 7. if I remember to write them in else. If not, as you see there, you get an error message that says. I know you're using the my-if macro. But none of the ways I know how to expand my if match. Because the one rule we have requires then and else in positions 3 and 5. So there I get 7. There's other things you could screw up. Maybe you put then here, and then it won't match in so, okay? So we really have defined our own macro. To us, it's not like my-if is in the language. It will get expanded to an if and then evaluated whenever we use, okay? So let's do another one, and now let's do this comment out one. So the idea here is that if you have something like comment-out how about car of null and then plus 3 4. That this should macro expand to just plus 3 4 completely throwing away the first line, and so it's, it's like you didn't have that first one there. So it's really the same idea. Define syntax, the name of our macro. Syntax rules. We don't have any extra words here, but you still have to have the list, so just make it empty, left parenthesis, right parenthesis. Our one case. And then when we see parentheses comment out 1 thing and then another thing. this is like e1 and e2, whatever those are, just replace it with the 2nd thing. You'll notice by the way I did not have these parentheses in here, that would add a calling instead as a function. And that is not what I want. Alright, so let's try this one out. how about I just paste down here exactly what we had. I think I'm missing oh, and then delete this, and I get 7, keeping in mind that car null would be an error, ok? So that's a couple examples. let me flip back to the slides for our. Third example. I want to redo My-delay, and My-force from when we studied promises. So, here on this slide you see how we used to do it. My-delay and My-force were functions. My-delay took a thunk, returned this mcons, my force took something that was one of these mcons's and then did the right thing for lazy evaluation. So the way you would use this, is if you have some function f here at the bottom that takes in a promise, a caller to f would have to write my-delay of a thunk that when called evaluates e and then f could force that thing, okay? So what we could do is define a macro for my-delay, so that programmers don't have to write that lambda, okay? Whether this is good style or not is somewhat debatable. But we can do this. It's no problem. A macro can pick up some syntax, put it under a lambda, and therefore it will delay evaluation, because after macro expansion, it's inside a function, and functions don't evaluate their bodies until you call them. You cannot implement this as a function, ok? So here's how the macro looks. If we define my-delay as a macro. That takes some expression, e, and replaces it with mcons of false and a thunk that evaluates e, then when we write this my-delay of e, that will not evaluate e. It will return an mcons. It has a thunk in it that we can call later to evaluate e. And this simply cannot be done with a function. There is no function in the world that can take an argument, e, and not evaluate it. Because in Racket, functions always have their arguments evaluated before you evaluate the body. So if you want to do this, so that programmers don't write the thunk when they call my-delay, a macro is really your, your option. That is your approach. Notice that having done it this way, we do not thunk the argument. If the programmer comes along and does write lambda parenthesis, parenthesis e, well now we're going to have a double thunk. We're going to have a thunk that when you call it returns a thunk. So you have to keep things straight. We are changing, how clients. Should use my delay by using this macro. So what about my force? Let me just go back here in a second. We had this function, my force. Should it be a macro? But I want to argue is that it should not. This is a perfectly good function. We want to just pass in something, have it use that You should leave it as a function. So let me show that with a code, so here I've got my delay, just like we defined it. Suppose you tried to do my force as a macro. So you just said all right, they can call my force with an e, and I'll expand that I will syntactically replace that with this if. What's the problem? The problem is now whatever they passed in, is going to get evaluated multiple times. That's not how the function works. Let me show this to you. If I call my-force, this is the function version, with some argument that has some side-effect, like printing hi, and then. has a promise in it. My-delay, this is a macro now so my-delay of plus 3 4. Print hi once evaluate to 7. But with this first macro version. , It prints "hi" five times. It's actually hard to think about how many times it would actually print it. it depends on this, but what we're doing is we're picking up this syntax and copying it into. This expansion. Macros are hard to reason about you don't want to do that. Here's a second version of the macro that actually does the right thing and it does it by taking in an E and creating a local variable that holds the results of evaluating E. So, that will evaluate E only once and then we just use X everywhere. And this macro will behave. How we want, which is to evaluate e once, and then do the right thing with the result. But there's just no reason to do this. Using a macro, just to have the exact same semantics as a function. Serves no useful purpose. So that's why I don't mind my-delay as a macro, but I don't want my-force as a macro. 'Kay? So, what we've seen here are the basics of syntax rules, how to use define syntax to define macros. We've often, also started to see, with this first my-force. The danger of not thinking carefully about when you evaluate things and how many times you evaluate things, and we'll continue our study of that in the next segment.