John Fremlin's blog: Complications in portably transforming Common Lisp

Posted 2009-08-16 02:46:00 GMT

Whether a particular declaration expression with declare, declaim or proclaim affects the variable namespace or the function namespace is defined by the semantics of the declaration itself. For example, (declare (type ...)) affects the variable namespace, whereas (declare (ftype ...)) affects the function namespace equivalently. This inconsistency is unfortunate, and a minor blot on the generally extremely well thought out CL standard.

It would have been easy to specify in the standard that all declarations affecting the function namespace must use #'names (i.e (function f) to refer to the function with name f) , which would allow transformers to rename functions and variables without understanding all declarations. Some declarations already support this, for example the declarations dynamic-extent or ignorable, which can either take a #'name for a function or just name for a variable binding. Alternatively, but more confusingly, (declare (declaration ...)) could give a sort of parameter type declaration as well.

The debate between a Lisp-1, where function and variable names share the same namespace, and a Lisp-2 where they in separate namespaces is canonically addressed in a slightly obsolete paper by Pitman and Gabriele (1988).

(The paper is slightly obsolete, in that it states a strict reading of the Common Lisp specification seems to imply that writing the following should be acceptable: ... (FLET ((CONS (X Y) (CONS Y X))) ...), which contradicts the ANSI Standard, Section, clearly stating that the consequences are undefined; this was added to the standard between 1988 and 1990.)

My interest is motivated by wanting to extend macroexpand-dammit to reduce Common Lisp to an even simpler form where it is easy to perform some escape analysis on local functions. A simplified approach is to first pass over all the code with an understanding of the full CL binding extents, and then rename all variable and other bindings to unique names so that later stages have an easier task of seeing where bindings are referenced. This would probably help for inlining functions as well.

However, as implementations may freely define new declarations, renaming function and variable bindings without understanding the semantics of each declaration would cause these declarations to potentially be lost or be applied to the wrong bindings.

Maybe there is an elegant way to do the escape analysis (obviously not the general inlining) without recourse to renaming. Alternatively, the parser could do the renaming with an understanding of the nine specified standard declarations and emit a warning on non-standard declarations. I guess as renaming is generally useful, I will have a go at this.

Any thoughts?

Post a comment