More on eval_lambda_expr: - Consider the following approach: Wherever you have (...((lambda (x) body) arg)...), replace ((lambda (x) body) arg) with body where with arg replacing x. This straightforward approach gets very time intensive if you have nested lambdas. So instead we implement a recursive method that evaluates the body in the extended environment that includes the evaluation of x to arg. - Here is the troublesome example mentioned at the end of the last lecture: ((lambda (y) (((lambda (y) (lambda (x) y)) 0) 1) ) 2) Let's evaluate this according to Scheme's evaluation rules. First, the rightmost y gets set to 0, so (lambda (x) y) evaluates to (lambda (x) 0). Thus, the (((lambda (y) (lambda (x) y)) 0) 1) evaluates to 0, regardless of the fact that the second argument is 1. Then, the outermost function is equivalent to (lambda (y) 0), which when applied to argument 2, still gives 0. Therefore the whole expression evaluates to 0. However, the eval_lambda_expr_dynamic function evaluates this same expression to 2, a pretty considerable discrepancy. The LISP founders noticed this discrepancy, and called it the FUNARG problem. They viewed it as a neat property of the language, rather than a bug. Thus, they created a special form FUNARG to handle this type of evaluation. Our eval_lambda_expr_dynamic is an implementation of what is called dynamic scope. Here, the association of an expression with a value is dependent on the order of evaluation within the expression. Scheme uses what is called static scope. Here, evaluation is independent of the order of evaluation. With static scope, you pay a little in terms of efficiency since you have to carry around an environment. However, you gain a lot in the optimizations that you can implement when things are handled statically, since it provides a more reliable structure. A Few Remarks on Scheme eval: - In Scheme, the empty environment is truly empty, not even having a function application method defined. - (eval (lambda ...)) can take an optional environment specification. The Scheme environment is handled with the namespace data type. Some Notes on Memory Usage: - The function (set-cdr! list suffix) sets the rest of list to suffix. Consider the list zerolist = (0). This is stored in memory as a pair of pointers n and p that point to the memory address of the first, 0, and rest, empty, respectively. Consider the function call (set-cdr! zerolist zerolist) This call sets p to the memory adress of zerolist. Thus, zerolist becomes an infinite list of zeroes.