Go to the first, previous, next, last section, table of contents.

Local Definitions

Scheme lets you define local procedures, scoped inside other procedures or blocks with local variables. This lets you "hide" procedures that only make sense in a certain context, so that they can only be called in that context.

You can define local procedures using let and lambda, like this:

(define (quadruple x)
   (let ((double (lambda (x)
                    (+ x x))))
      (double (double x))))

Here we've defined a procedure named quadruple, with a local variable named double; its value is a procedure that will double its argument value, created with lambda.

Notice that when we call double from inside the procedure quadruple, we call it by the name double, which is really the name of a local variable. That's okay, because there's no difference between variable names and procedure names--a call to a named procedure is always a lookup of a variable value followed by a call to the procedure it points to.

Also notice that the inner procedure's argument variable x shadows the outer procedure's argument variable x. Inside the body of double, it refers to double's argument, but outside it doesn't. (The code might be easier to read if we chose different names for the two procedures' arguments, but this is just for illustration.)

As with a top-level definition, we can write a local definition using define instead of let. For example, we could have written the above procedure as:

(define (quadruple x)
   (define (double (x)
              (+ x x))))
   (double (double x))))

A local define acts a lot like let with lambda. (Actually, it's exactly like a letrec with lambda, but we haven't discussed letrec yet; we will later.)

There's a restriction on internal defines--they must be at the beginning of the procedure body (or the beginning of another body, like a let body, before the normal executable expressions in the body.

Local procedure definitions follow the normal lexical scope rule, like nested lets. For example, in the above example, the formal argument x of double is local to the body of double---it's a different variable x than the argument x of quadruple.

(define (quadruple x)
   (define (double (x)
 +--------------------------+
 |           +--------+     |
 |           | (+ x x)|)))  |
 |           +--------+     |
 |  (double (double x))     | ))
 +--------------------------+

Here the inner box is the scope of double's argument x, and the outer one is the scope of the variable double.

We could have used a different name for the argument to the local procedure, and it wouldn't change the meaning of either procedure:

(define (quadruple x)
   (define (double (y)   ; local defn. of double
              (+ y y)))  ;    body of local procedure
   (double (double x)))  ; body of quadruple

On the other hand, since there are no local bindings of +, + refers to whatever it refers to in the context where quadruple is defined. Assuming that quadruple is a top-level procedure, not a local procedure in some other scope, + refers to the top-level binding of +. (Remember that a procedure name is really just a variable name, so the scope rules for variables apply to procedure names too.)


Go to the first, previous, next, last section, table of contents.