Binding occurs in two situations in LISP:
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 )
)
)
)
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)
Due to dynamic scoping, the argument name value in the definition of applyIncrement can block access to a global atom value.
E.g.,
( lambda ( x ) ( * value x ))is vulnerable to being called in an environment in which value is rebound.
Two solutions:
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. |
Formal-actual binding can be implemented in two ways:
| + | Less searching is done to locate a variable. |
See Implementation of Dynamic Scoping from the XEmacs Lisp Reference Manual on deep vs. shallow binding.