There is more to calling a procedure than evaluating its body. Procedures are interesting because they change the way symbols are evaluated; references to names of arguments within the procedure need to be resolved within the correct local environment rather than from the global symbol table.
It simplifies matters a bit to see that there does not need to be a distinction between arguments and ``local variables'' (let-bound variables); let is just a rearranged lambda. So you only need to worry about arguments.
eval takes an argument specifying the current local environment. To call a procedure, you'll need to allocate a new environment to pass to eval. Arguments will be bound to their values within this environment.
The most difficult part of binding arguments is handling improper argument lists. Scheme allows a user-defined function to take a variable number of arguments when its formal argument list is improper:
(define (varargs a b c . d)
....
Let's say this function is called on the arguments (1 2 3 4 5 6). Corresponding parts of the formal and actual arguments are matched up:
| Formal arg | value |
|---|---|
| a | 1 |
| b | 2 |
| c | 3 |
| d | (4 5 6) |
The way to understand this is that a, b, and c are in the cars of their respective cons cells, so they are assigned to cars of the argument list. d is in the cdr of the third cons, so it gets assigned the cdr of the third cons in the actual arguments.
As long as each function invocation allocates its own environment, functions can call themselves or each other freely in any combination. However, this is not sufficient to handle the case of nested functions, where one function (often a lambda) occurs lexically within the body of another.
Scheme uses lexical scope, a scoping rule which stipulates that nested functions must be able to see the local variables of any enclosing functions. Be sure you understand that this has nothing to do with functions called from other functions; it only affects functions whose code occurs physically inside that of other functions.
The function find-gt below contains a lambda that has its own local variable a and also uses variable x from its enclosing function:
(define (find-gt l x)
(filter (lambda (a) (> a x)) l))
What happens if a nested function has arguments with the same names as
its enclosing function?
To deal with nested functions, we need to evaluate symbols using a chain of environments. If a symbol is not found in the closest lexical environment, we step out to the next enclosing environment and try that next. The cool part is that the function invocation that created this enclosing environment might have terminated--its environment lives on! Recall that when a function returns a function, the returned function can still use its entire lexical environment when invoked later.
For this to be possible, you need to save a pointer to the current local environment whenever a new procedure is created. This saved environment will be the second link on the chain of environments when the procedure is invoked in the future.
Let's look at everything that happens as the interpreter evaluates an expression. An exposition such as this is formally known as a shaggy dog story. Our example Scheme expression will be
((lambda (x y) (+ (* 2 x) y)) (+ 5 5) 9)
We begin with the expression as a value (specifically, a pair) read by your parser.
(named-lambda (quote -anon-) (x y) (+ (* 2 x) y))
Try to list all the places in this process where type errors could occur.
takes advantage of a convenient C++ feature that lets the programmer specify default values for function arguments. When an argument has a default value, it can be omitted in a call to the function and the compiler will automatically pass the default for you.
Default values are specified in the function prototype, but not in the function definition:
In value.h:
static void type_check(tag got, tag expected, string context = "");
In value.cc:
void value::type_check(tag got, tag expected, string context)
{
...
}
This document was generated using the LaTeX2HTML translator Version 2002-2-1 (1.71)
Copyright © 1993, 1994, 1995, 1996,
Nikos Drakos,
Computer Based Learning Unit, University of Leeds.
Copyright © 1997, 1998, 1999,
Ross Moore,
Mathematics Department, Macquarie University, Sydney.
The command line arguments were:
latex2html -no_navigation -split 0 sec10.tex
The translation was initiated by CS51 Course Library on 2008-05-05