Augustana University College

COMPUTING SCIENCE 370
Programming Languages


LISP -- Name Structures



Binding

Binding occurs in two situations in LISP:

  1. Name-value binding
  2. Formal-actual binding

    E.g.,
    > (defun setZero (anAtom) (set 'anAtom 0)))
    SETZERO
    > (set 'one 1)
    1
    > (setZero 'one)
    0
    > one
    1

    So what's the point, you may be asking, of passing an argument into a function if the function can't change the value of the argument anyway? In the case of setZero, there basically is no point -- since setZero just sets a local variable to 0, then returns the value to which it set the local variable (0), you might as well have just used the atom 0.
         However, in the general case, the value of the argument is used to initialize the local variable, and you might want to set the local variable to a different value for subsequent use inside the function; for example, the following function stores the new value of the argument so it can both print it and use it to call itself recursively:

       (defun squareRoots ( val )
          ( cond
             (( > val 2) 
                ( setq val ( sqrt val )) 
                ( print val )
                ( squareRoots val )
             )
          )
       )
    

Static and Dynamic Scoping

Static scoping
A subprogram is called in the environment of its definition.
Dynamic scoping
A subprogram is called in the environment of its caller.

Classical LISP uses dynamic scoping.

E.g., a function which increments its second argument, then applies its first argument as a function; i.e.,

applyIncrement(f, v) = f(v + 1)

The Functional Argument (funarg) Problem

Due to dynamic scoping, the argument name value in the definition of applyIncrement can block access to a global atom value.

E.g.,

Two solutions:

  1. Introduce a special mechanism to force the bindings in a lambda expression to be bound in the environment of its definition rather than that of its caller.

    closure
    A record containing an instruction pointer and an environment pointer.

    The special form function implements closure in classical LISP.

    E.g.
    > (set 'value 2)
    2
    > (applyIncrement (function (lambda (x) (* value x))) 3 )
    8

    + Provides a mechanism to avoid the funarg problem.
    - Ad hoc approach to the problem of dynamic scoping.
    - Complicates function application, as there are two types of expr: lambda expressions and closures.

  2. Revise the language to use static scoping (e.g., Scheme, Common LISP).

Implementation of Binding

Formal-actual binding can be implemented in two ways:

  1. Deep binding -- Function activation causes the parameter variable(s) to be placed on the run-time stack; deactivation causes them to be popped.

  2. Shallow binding -- Each variable has its own stack. Function activation causes new copies of its parameter variables to be pushed onto their stacks; deactivation causes them to be popped.

    + Less searching is done to locate a variable.

    See Implementation of Dynamic Scoping from the XEmacs Lisp Reference Manual on deep vs. shallow binding.

Copyright © 2000 Jonathan Mohr