2
votes

So here's a question about scheme variable binds. Let's say I have the following function:

(define undefinedTest (lambda (y) (list x y)))

This will warn of x being an unbound variable when run in Guile-Scheme 2.0.3. If I then execute the following statement

> (let ((x 'something)) (undefinedTest 'else))

I will get an error and the option to debug it. However if I execute the following statements:

> (define x 'something)
> (undefinedTest 'else)

I get the expected answer of (something else). Why is scheme able to bind x when it is defined at the top-level, but not when it is bound by let. Is this because when the function is defined it is also defined at the top-level, and so when scheme go to search its nearest enclosing environment, the let environment is not actually "enclosing" as it still starts its search at the "top-level"?

3
Ensure the title aligns with the "real question" in the post.user166390

3 Answers

5
votes

Scheme uses lexical scoping, not dynamic scoping. So the x the undefinedTest sees is the x that is lexically visible from that function, which in this case, as you've already noted, is the top-level scope.

1
votes

Lexical scope is a core feature of Scheme. With lexical scoping, you can always tell which bindings are visible to a function, because they are those visible at the point where the function is defined. Dynamic scoping, in contrast, has a tendency to create surprises which can be hard to foresee and equally difficult to debug.

1
votes

When undefinedTest was defined, it enclosed the environment in which it was defined; given that it was defined at the top level, it will only "see" its formal parameter y and the global environment - and the global environment doesn't contain x at that point. It's like that because Scheme is lexically scoped.

I tested the code in the question in Racket and the first line fails with the error: expand: unbound identifier in module in: x - meaning that it's not even a valid definition as interpreted by Racket.

The same example would work in a language with dynamic scoping, Scheme uses lexical scoping (a.k.a. static scoping.)