Differences Between Lexical and Dynamic Binding

As we discussed before (see let Prevents Confusion), when you create local variables with let under lexical binding, those variables are valid only within the body of the let expression. In other parts of your code, they have other meanings, so if you call a function defined elsewhere within the let body, that function would be unable to “see” the local variables you’ve created. (On the other hand, if you call a function that was defined within a let body, that function would be able to see—and modify—the local variables from that let expression.)

Under dynamic binding, the rules are different: instead, when you use let, the local variables you’ve created are valid during execution of the let expression. This means that, if your let expression calls a function, that function can see these local variables, regardless of where the function is defined (including in another file entirely).

Another way to think about let when using dynamic binding is that every variable name has a global “stack” of bindings, and whenever you use that variable’s name, it refers to the binding on the top of the stack. (You can imagine this like a stack of papers on your desk with the values written on them.) When you bind a variable dynamically with let, it puts the new binding you’ve specified on the top of the stack, and then executes the let body. Once the let body finishes, it takes that binding off of the stack, revealing the one it had (if any) before the let expression.