[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

User-defined Mapping Functions



     As I understand it, you end up with something like:

(defun mapappend (func lst)
    (apply (function append) (mapcar func lst)))

(defun anyequalp (atm lst)
    (mapappend (function (lambda (x) (and (equal atm x) (list x)))) lst))

And then...

| Things work great.  NOW, I try to compile my code and I get the following
| messages (paraphased) ...

| anyequalp: Warning: in line lambda (some huge number)
| Warning: atm declared special by compiler.

     It turns out that the compiler does handle the built-in mapping
functions specially: it treats them as macros that expand into do-loops.
This is why no in-line-lambda is created in that case.  When it *is*
created, the compiler forgets most of the context from which it came
and treats it as a separate function.  Then, the use of 'atm' in the
local function is no longer seen to refer to the 'atm' in 'anyequalp'.
The compiler notices that 'atm' is used without being bound to anything
(say by being a formal parameter of the function and thus bound to the
corresponding argument) and, so it has some chance of referring to
something, declares it special.  This would work perfectly except that
the 'atm' in 'anyequalp' is not special; if you were to put a

	(declare (special atm))

before the definition of 'anyequalp', everything would work out.  It works
fine in the interpreter because then all variables are essentially 'special'.
(I guess I'm assuming here that you know what special variables are.)

     Whether this should be called a bug is not clear.  In a Lisp
that properly implements lexical scoping (e.g. Common Lisp, T), the
"textual" context of the local lambda would make a difference and you
would not need the 'special' declaration.  Another approach would be
to require such declarations in the interpreter as well.  However,
Lisp has traditionally taken a more expedient, although perhaps less
correct, approach, as in Franz. 

     If you want to avoid special declarations altogether, you could
define 'mapappend' as a macro instead:

	(defmacro mapappend (fn &rest lists)
	  `(apply #'append (mapcar ,fn . ,lists)))

This also has the advantage of making it easy to define it so that the
function can be mapped over several lists at once, as in the built-in
mapping functions.

     Hope this is helpful,

	Jeff Dalton
	Dept. of Artificial Intelligence
	University of Edinburgh