Let scoping

Table of Contents

toggle-theme.png

Question

Why does this return 2 and not 3?

(let ((c 1))
  (let ((c 2)
        (a (+ c 1)))
    a)); RETURNS 2

The reason here is because of how the scoping works in Lisp when using let. When you use let, variables that you’re binding aren’t able to see variables bound before it in the same let. If we did

(let ((a 1)
      (b (+ a 1)))
  (print b))

This would give us an error, because a isn’t available when binding b. So logically, Lisp would need to look to the enclosing scopes to try to find that variable a. That’s what’s happening in the example above as well. Lisp isn’t able to bind a to the value of the c bound immediately before it, so Lisp looks to the enclosing scope and find that there’s a variable c in that scope, and uses it.

If we change our inner let to be let*, then we get another interesting question:

(let ((c 1))
  (let* ((c 2)
         (a (+ c 1)))
    a))

Now what will the value of a be? In this case, it’ll be 3, because our second c shadows the value of the first. So whenever we refer to c inside our nested let* here, it’ll be referring to the c declared in that block.

(let ((c 1))
  (let* ((c 2))
    (setf c 20)
    (print c))
  (print c))

What do you think this program will output now?

Author: Philip Dumaresq

Email: phdumaresq@protonmail.com

Created: 2021-03-13 Sat 19:09