[MUSIC] So, now that we've discussed how local bindings work and the semantics of them, I just want to tell you the semantics of top-level bindings that defines in a file because it would be an omission not to go through that. So, the short version is, when you have a bunch of bindings in a file, they work like a letrec, or they work just like a local define. So, you can have things referred to later by names. So, like in ML, the things are evaluated in order and you can refer to early bindings. But unlike ML, you can also refer to later bindings. Now, because this evaluated an order issue, you should only refer to later bindings in function bodies, and you should make sure that those functions do not get called until after the thing you're referring to has had its expression evaluated. Unlike insider functions where you get an undefined result, you'll actually get an error in racket, but that's a detail that we don't need to focus on. but, you might be thinking, oh, great, finally I can refer to later things. Everything is better. Well, it turns out there's a couple of disadvantages to this semantics. One, as we've seen, is you can get these errors if you refer to something too early. But the second is, you cannot shadow inside of a file. That wouldn't mean anything. If you have two bindings of the same variable in the same file, this doesn't make any sense because we're trying to add them to the same environment and you'll get an error if you try to do that. So, quick example here. this is just silly code. In this first line, I define a function, f. And if you look in its body, it not just uses its argument but it also uses some variable b that is actually introduced later in the file. This is okay because the body of f is not called until after we have the binding b initialized to 3. In fact, in this file, we don't call it at all. But once someone uses this module, uses this file or clicks Run, we will be bound to 3 and any call to f will work correctly. Now, you can go ahead and use in earlier binding, even not inside a function body. This works just like in ML, or just like with a letrec. we evaluate things in order. So, by the time we get to the +b4, b is already 3, so c would be evaluated to 7, there's no trouble. You cannot do this to a later thing. So, this is what I've been emphasizing. If I uncomment this line, then trying to execute this line d will give an error, I can just click run here. It says reference to an identifier before its definition, that's exactly the mistake we made, okay? so and then on this last line, define f17. This would also be an error because you can't introduce two variables f in the same file like this, you would get duplicate definition for identifier in f, okay? So, that's the advantages and disadvantages of this letrec-style semantics for the top-level bindings, and that's really what you need to know from this segment. Now, a couple other details, just to finish up. One is the REPL doesn't quite work like letrec. It doesn't quite work like let star. In fact, it doesn't quite work properly at all. And I'm not going to go into the details of how the REPL works because in normal uses, the REPL will do what you want, just like we've been a REPL in ML, and now in Racket. But, it turns out there's some things that don't work well. If you shadow something that's already been defined even in the standard library, and you're defining a recursive function, things can go very wrong. And so, the easy work around is in the REPL, do not define your own recursive functions. It's fine to call recursive functions that have been defined by a file that you are running. Don't define your own in the REPL, go ahead and put them in a file and then we can avoid this issue. And then, one other optional thing is later in the course, I'd like to at least optionally study Racket's module system. And I'm being technically incorrect here. Inside of file and Racket is not really top level bindings, which is what I called the segment. In Racket, every file is implicitly in its own module. Now, in that module still has letrec style semantics, so all the code I showed you is correct. But it turns out that across files, it's not one big letrec, it's actually a separate letrec for each file. And you can include things from another file. And you can shadow things from another file from another module. So, in fact, since plus is just a function and it's just defined in some other module that's part of the standard library, you could even shadow the plus function inside your own file, but each file can only define it once. Of course, that sort of shadowing is, is poor style, but it helps explain Racket's module system. Which as I mentioned, will be an optional topic later in the course.