Subject: [clisp-list] AIMA Code compilation problem (WITH-SIMPLE-RESTART redefinition)

From: Paolo Amoroso <[email-masked]>
Date: Fri, 22 Dec 2000 11:12:19 +0100

I have a compilation problem with the source code of the book "Artificial
Intelligence - A Modern Approach" by Norvig and Russel (0.95 AIMA Code,
Patriots Day Version, 21-Apr-1997). I use CLISP 2000-03-06 (March 2000)
under Red Hat Linux 6.2.

After customizing aima.lisp as explained in the documentation, I load it
and start compilation:

[7]> (load "aima.lisp")
;; Loading file aima.lisp ...
;;  Loading file
/home/paolo/Lisp/common-lisp/code/aima/utilities/utilities.lisp ...
;;  Loading of file
/home/paolo/Lisp/common-lisp/code/aima/utilities/utilities.lisp is
finished.
[...]
;;  Loading file
/home/paolo/Lisp/common-lisp/code/aima/utilities/test-utilities.lisp ...
;;  Loading of file
/home/paolo/Lisp/common-lisp/code/aima/utilities/test-utilities.lisp is
finished.
;; Loading of file aima.lisp is finished.
T
[8]> (aima-compile)
Compiling file
/home/paolo/Lisp/common-lisp/code/aima/utilities/utilities.lisp ...

Compilation of file
/home/paolo/Lisp/common-lisp/code/aima/utilities/utilities.lisp is
finished.
0 errors, 0 warnings
;; Loading file
/home/paolo/Lisp/common-lisp/code/aima/utilities/utilities.fas ...
;; Loading of file
/home/paolo/Lisp/common-lisp/code/aima/utilities/utilities.fas is finished.
[...]
Compiling file /home/paolo/Lisp/common-lisp/code/aima/utilities/cltl2.lisp
...
** - Continuable Error
Redefining the COMMON LISP macro WITH-SIMPLE-RESTART
If you continue (by typing 'continue'): The old definition will be lost
1. Break [9]> 

The code that triggers the error is in utilities/cltl2.lisp and is intended
for old Lisp systems, i.e. pre-CLtL2:

(define-if-undefined
  
(defmacro with-simple-restart (restart &rest body)
  "Like PROGN, except provides control over restarts if there is an error."
  (declare (ignore restart))
  `(progn ,@body))

(defmacro destructuring-bind ... )

  ) ; end define-if-undefined

The DEFINE-IF-UNDEFINED macro is defined in utilities/utilities.lisp:

(defmacro define-if-undefined (&rest definitions)
  "Use this to conditionally define functions, variables, or macros that
  may or may not be pre-defined in this Lisp.  This can be used to provide
  CLtL2 compatibility for older Lisps."
  `(progn
     ,@(mapcar #'(lambda (def)
		   (let ((name (second def)))
		     `(when (not (or (boundp ',name) (fboundp ',name)
				     (special-form-p ',name)
				     (macro-function ',name)))
		       ,def)))
	       definitions)))

I am perplexed because CLISP does have WITH-SIMPLE-RESTART, so the test in
the WHEN form should evaluate to NIL--and indeed it does if evaluated at
the listener. Any suggestions?

Paolo
-- 
EncyCMUCLopedia * Extensive collection of CMU Common Lisp documentation
http://cvs2.cons.org:8000/cmucl/doc/EncyCMUCLopedia/

---

From: Bruno Haible <[email-masked]>
Date: Fri, 22 Dec 2000 19:31:04 +0100 (CET)

> the listener. Any suggestions?

This relates to the ANSI CL issue "DEFINING-MACROS-NON-TOP-LEVEL:ALLOW",
and both the code above and CLISP's compiler don't conform to CLHS.

CLHS says about DEFMACRO:
   If a defmacro form appears as a top level form, the compiler must
   store the macro definition at compile time, so that occurrences of
   the macro later on in the file can be expanded correctly. Users must
   ensure that the body of the macro can be evaluated at compile time
   if it is referenced within the file being compiled.

This means that in code like the above

   (when (not (or (boundp 'with-simple-restart) ...))
     (defmacro with-simple-restart ...)
   )

the 'defmacro' form is not at top level and therefore will have no
effect during compile-file. That's why I consider the code above
broken.

But CLISP is broken as well: It must not evaluate the
   (not (or (boundp 'with-simple-restart) ...))
condition at compile-time. According to ANSI CL, it should produce
code for the defmacro form, but otherwise during the compilation
behave as if the form wasn't there. That's not what CLISP does. CLISP
chooses to always evaluate the form, because that copes better with
old CLtL1 programs that do things like

    (if (not (find-package ...))
      (defpackage ...) ; or even worse: (make-package ...)
    )

It's related to EVAL-WHEN, arguably the darkest spot of the CL
specification.

Bruno