[1] Even so, there will remain important aspects of the evaluation process that are not elucidated by our evaluator. The most important of these are the detailed mechanisms by which functions call other functions and return values to their callers. We will address these issues in chapter 5, where we take a closer look at the evaluation process by implementing the evaluator as a simple register machine.
[2] If we grant ourselves the ability to apply primitives, then what remains for us to implement in the evaluator? The job of the evaluator is not to specify the primitives of the language, but rather to provide the connective tissue—the means of combination and the means of abstraction—that binds a collection of primitives to form a language. Specifically:
  • The evaluator enables us to deal with nested expressions. For example, although simply applying primitives would suffice for evaluating the expression 2 * 6, it is not adequate for handling 2 * (1 + 5). As far as the operator * is concerned, its arguments must be numbers, and it would choke if we passed it the expression 1 + 5 as an argument. One important role of the evaluator is to choreograph composition so that 1 + 5 is reduced to 6 before being passed as an argument to *.
  • The evaluator allows us to use names. For example, the addition operator has no way to deal with expressions such as x + 1. We need an evaluator to keep track of names and obtain their values before invoking the operators.
  • The evaluator allows us to define compound functions. This involves knowing how to use these functions in evaluating expressions and providing a mechanism that enables functions to accept arguments.
  • The evaluator provides the other syntactic forms of the language such as conditionals and blocks.
4.1  The Metacircular Evaluator