The following code is confusing me:
(define (even-or-odd-letrec x)
((lambda (internal-even? internal-odd?)
(set! internal-even? (lambda (n)
(if (= n 0) 'even
(internal-odd? (- n 1)))))
(set! internal-odd? (lambda (n)
(if (= n 0) 'odd
(internal-even? (- n 1)))))
(internal-even? x))
#f #f))
As I read it, the environments are as follows:
- Inside the environment of
even-or-odd-letrec,internal-even?andinternal-odd?are initially bound to#f. Their parent environment is the global environment. set!then changes these two values to the obviouslambdas, but does not change the environments.- Because the environments haven’t changed, any calls to
internal-even?will look in the global environment forinternal-odd?and find nothing.
So how does this code work?
>Solution :
Answering the title of your question: no, setting does not create any new frames.
Setting sets the value of a binding in the current environment frame. Whatever the old and new values might be. Function or no, makes no difference.
Again, set! does not change values. It changes bindings’ values. A binding is a pairing of a name and its value. Set!ting changes that name’s bound value.
Seen as a named pointer, after being re-set!, a name points to a new value — that value which was supplied to set! as the second argument.
So contrary to what you say, set! does change the current environment frame — it mutates its binding for the given name that is sets.
+---------------+ +---------------+
| n1 ---> v1 | | n1 ---> x |
| n2 ---> v2 | (set! n1 x) | n2 ---> v2 |
|---------------| -------------> |---------------|
| ..code... | | ..code... |
|_______________| |_______________|
"Any call to internal-even? will" ….. stop! this isn’t the right way to look at it.
Any reference to internal-even? inside the lambda-created frame will be resolved by looking up the value under the name internal-even? in that same frame, and all will work out fine.