From: Bruno H. <br...@cl...> - 2007-10-08 22:43:23
|
Sam wrote: > Eli Bendersky wrote: > > > > Consider this code: > > > > (defun printer (val) > > (lambda () (format t "~a~%" val))) > > > > (setq printer-of-10 (printer 10)) > > (funcall printer-of-10) > > > > It prints "10" as expected. However, consider this code: > > > > (defvar val 12) > > (funcall printer-of-10) > > > > It prints 12 ! > > this is, of course, not compliant. You mean, clisp's result are not ANSI CL compliant? Nah. The program above is not conforming ANSI CL, therefore clisp can produce arbitrary results. Why is it not conforming ANSI CL? Because of section 3.2.2.3 Semantic Constraints: "All conforming programs must obey the following constraints ...: Special proclamations for dynamic variables must be made in the compilation environment." The code shown above has a SPECIAL proclamation for the variable VAL in the execution environment (before the funcall) but not in the compilation environment: at the moment the PRINTER function is defined, is it not known as a SPECIAL variable. Therefore the code is not conforming. The same holds also for macros. Before defining a function that uses a macro, that macro must have been defined. > ISTR that this behavior was implemented intentionally to ease > interactive development, because "usually" the printer above would be > followed by a (forgotten) defvar. Yes, exactly. When a user compiles a program, the compiler is allowed to remember the information whether a variable was SPECIAL or not, because that allows the compiler to generate more efficient code. But in interpreted code, when the user changes the state of a variable, or redefines a macro, he does *not* want to re-evaluate all DEFUNs that use the variable or macro. ANSI CL gives the implementation freedom regarding interpreted evaluation, how much it wants to remember / cache, and how much it wants to evaluate according the current environment, if the environment has changed. clisp implements "ad-hoc lookup" for variables, but not for macros. It would be useful to change clisp to take into account changed macro definitions during the interpretation of function bodies. It currently does not do so, for efficiency reasons: macro expansion is slow. But with a more intelligent caching mechanism, this could be remedied. If the interpreted function would not only cache the function body's expansion but also the vector of global macros that this expansion depended on, clisp could decide to throw away the cached macro expansion and redo the expansion when it sees that a macro's definition has changed. Test case: (defmacro pair (x y) `(cons ,x ,y)) (defun foo (a b c d) (pair (pair a b) (pair c d))) (foo 1 2 3 4) => ((1 . 2) 3 . 4) ; user not satisfied with the result (defmacro pair (x y) `(list ,x ,y)) (foo 1 2 3 4) => ((1 2) (3 4)) Bruno |