The overall specification of how the interpreter evaluates a combination function application remains the same as when we first introduced it in section 1.1.4:
In the environment model of evaluation, a procedure function is always a pair consisting of some code and a pointer to an environment. Procedures Functions are created in one way only: by evaluating a lambda lambda expression. This produces a procedure function whose code is obtained from the text of the lambda lambda expression and whose environment is the environment in which the lambda lambda expression was evaluated to produce the procedure. function. For example, consider the procedure definition function declaration
Original | JavaScript |
(define (square x) (* x x)) | function square(x) { return x * x; } |
Original | JavaScript |
(define square (lambda (x) (* x x))) | const square = x => x * x; |
Figure 3.3 Figure 3.4 shows the result of evaluating this define expression. declaration statement.
Original | JavaScript | |
The global environment encloses the program environment. To reduce clutter, after this figure we will not display the global environment (as it is always the same), but we are reminded of its existence by the pointer from the program environment upward. |
Original | JavaScript | |
In general, define creates definitions by adding bindings to frames. |
Original | JavaScript | |
Original | JavaScript | |
In general, const, function, and let add bindings to frames. Assignment is forbidden on constants, so our environment model needs to distinguish names that refer to constants from names that refer to variables. We indicate that a name is a constant by writing an equal sign after the colon that follows the name. We consider function declarations as equivalent to constant declarations;[4] observe the equal signs after the colons in figure 3.4. |
Now that we have seen how procedures functions are created, we can describe how procedures functions are applied. The environment model specifies: To apply a procedure function to arguments, create a new environment containing a frame that binds the parameters to the values of the arguments. The enclosing environment of this frame is the environment specified by the procedure. function. Now, within this new environment, evaluate the procedure function body.
To show how this rule is followed, figure 3.5 figure 3.6 illustrates the environment structure created by evaluating the expression (square 5) square(5) in the global program environment, where square is the procedure function generated in figure 3.3. figure 3.4. Applying the procedure function results in the creation of a new environment, labeled E1 in the figure, that begins with a frame in which x, the formal parameter for the procedure, function, is bound to the argument 5. Note that name x in environment E1 is followed by a colon with no equal sign, which indicates that the parameter x is treated as a variable.[5] The pointer leading upward from this frame shows that the frame's enclosing environment is the global program environment. The global program environment is chosen here, because this is the environment that is indicated as part of the square procedure function object. Within E1, we evaluate the body of the procedure, function, (* x x). return x * x;. Since the value of x in E1 is 5, the result is (* 5 5), 5 * 5, or 25.
Original | JavaScript | |
The environment model of procedure function application can be summarized by two rules:
Original | JavaScript | |
We also specify that defining a symbol using define creates a binding in the current environment frame and assigns to the symbol the indicated value. | We leave this out of the JavaScript version, because it is discussed in more detail in section 3.2.4. |
Original | JavaScript | |
Evaluating the expression (set! variable value) in some environment locates the binding of the variable in the environment. For this, one finds the first frame in the environment that contains a binding for the variable and modifies that frame. If the variable is unbound in the environment, then set! signals an error. | Finally, we specify the behavior of assignment, the operation that forced us to introduce the environment model in the first place. Evaluating the expression $name$ = $value$ in some environment locates the binding of the name in the environment. That is, one finds the first frame in the environment that contains a binding for the name. If the binding is a variable binding—indicated in the frame by just : after the name—that binding is changed to reflect the new value of the variable. Otherwise, if the binding in the frame is a constant binding—indicated in the frame by := after the name—the assignment signals an "assignment to constant" error. If the name is unbound in the environment, then the assignment signals a "variable undeclared" error. |
These evaluation rules, though considerably more complex than the substitution model, are still reasonably straightforward. Moreover, the evaluation model, though abstract, provides a correct description of how the interpreter evaluates expressions. In chapter 4 we shall see how this model can serve as a blueprint for implementing a working interpreter. The following sections elaborate the details of the model by analyzing some illustrative programs.