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.