Rather, there is nesting. Nesting isn't the same thing as scoping.
> Variables will always be unbound in the reverse order they were bound.
Counterexample:
(let* ((x 1) (y (* 2 x)) (z (+ x y))) ;; bound in sequence
) ;; unbound in parallel
We could have an unlet operator which introduces a new scope that explicitly removes a binding:
(let (x) ; #define x
(let (y) ; #define y
(unlet (x) ; #undef x
;; y bound, x free
))) ; #undef y, #undef x
Basically, #define and #undef can be regarded as having proper nesting: each one creates a new scope that lasts unti the end of the translation unit, nested relative to the previous scope.
You can do something like this in c:
Which is essentially equivalent to [(])