What is the purpose of &environment in Common Lisp?

common-lisp, environment

Solution

Doc

Macro Lambda Lists:

`&environment` is followed by a single variable that is bound to an environment representing the lexical environment in which the macro call is to be interpreted. This environment should be used with `macro-function`, `get-setf-expansion`, `compiler-macro-function`, and `macroexpand` (for example) in computing the expansion of the macro, to ensure that any lexical bindings or definitions established in the compilation environment are taken into account.

Explanation

Operators which define macros (local or global) have to define how code is expanded before being evaluation or compiled, and thus may need to expand existing macros, whose expansion may depend on the environment - so the macro definitions need the environment.

Not a Special Variable

Special variables are more dangerous because the user might rebind them and because they are harder to handle correctly in multi-threaded code.

Example

All over the `places.lisp`:

(defmacro psetf (&whole whole-form
                 &rest args &environment env)
  (labels ((recurse (args)
             (multiple-value-bind (temps subforms stores setterform getterform)
                 (get-setf-expansion (car args) env)
               (declare (ignore getterform))
               (when (atom (cdr args))
                 (error-of-type 'source-program-error
                   :form whole-form
                   :detail whole-form
                   (TEXT "~S called with an odd number of arguments: ~S")
                   'psetf whole-form))
               (wrap-let* (mapcar #'list temps subforms)
                 `(MULTIPLE-VALUE-BIND ,stores ,(second args)
                    ,@(when (cddr args) (list (recurse (cddr args))))
                    ,@(devalue-form setterform))))))
    (when args `(,@(recurse args) NIL))))

From `iolib/src/new-cl/definitions.lisp`:

(defmacro defconstant (name value &optional documentation
                       &environment env)
  (destructuring-bind (name &key (test ''eql))
      (alexandria:ensure-list name)
    (macroexpand-1
     `(alexandria:define-constant ,name ,value
        :test ,test
        ,@(when documentation `(:documentation ,documentation)))
     env)))

Problem

I am confused about the &environment parameter in common lisp. In particular, what is it useful for, and why is it a parameter, rather than a special variable? EDIT: It would also be nice to see a concrete example of how `&environment` would be used in code.

Original source