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

KCL and #<...> in code



> (defmacro make-arithmetic-list-operation 
>           (operation specialized-image-operation)
>   (let 
>       ((original-function 
> 	(symbol-function (find-symbol (symbol-name operation) 'lisp))))
>     
>     `(setf (symbol-function ',operation)  
>       '(lambda (&rest args)	  
> 	(let ((images? (mapcar #'internal-image-p args)))
> 	  (cond
>           ;; ...
> 	    (t               
> 	     (apply ,original-function  args))))))))
> 
> Then I would do:
> 
>   (make-arithmetic-list-operation + image-+)
> 
> This did not work in a compilation environment because KCL inserted a
> function definition such as #<compiled lisp::+> in the place of
> ``original-function''. Since #< > forces an error when read, I could
> not compile the new +.  This works OK in LUCID and CMUCL -- is this
> just dumb luck on my part, or is KCL in error?  The work-around I
> adopted was to use (gentemp) to create an symbol to hang the old
> function on.

I don't think this is a bug in KCL, and I am surprised to hear it
works in CMU CL.  There are two problems:

  1. Objects such as functions are not allowed in code being
     compiled by COMPILE-FILE.  (The only objects that are allowed
     are those for which "similar as constants" is defined.  See
     CLtL II.)

  2. You use a quoted LAMBDA-expression as the funciton, which again
     is not allowed in this context in "new" (CLtL II) Common Lisp.

Consider the following file:

   (defmacro fun (name)
     (symbol-function name))

   (defun f (x)
     (funcall (fun list) x x))

And now in CMU CL:

   * (compile-file "test.cl")
   Python version 1.0(15a), VM version SPARCstation/Sun 4 ...n
   Compiling: /user/2/jeff/unsafe/test.cl 16 MAR 92 04:43:41 pm

   Converted FUN.
   Compiling DEFMACRO FUN: 

   File: /user/2/jeff/unsafe/test.cl

   In: DEFUN F
     (FUN LIST)
   ==>
   #<Function LIST {100B1B9}>
   Error: FUNCTION constants not supported.

Etc.  And then:

   Error in function C::DUMP-NON-IMMEDIATE-OBJECT.
   This object cannot be dumped into a fasl file:
    #<Function LIST {100B1B9}>

Ok, now try a LAMBDA-expr as a function (still in CMU CL):

   * (setf (symbol-function 'g) '(lambda (x) (* x x)))

   Type-error in KERNEL:%SP-SET-DEFINITION:
     (LAMBDA (X) (* X X)) is not of type FUNCTION


There are ways to get around this problem without using generated
symbols.  One might be to use LOAD-TIME-VALUE, but lots of Common
Lisps don't have it yet.  Another to take advantage of lexical
scoping (and to do more things at load time).  Eg,

(defmacro define-arithmetic-list-operation (name)
  (let ((original-name
          (find-symbol (symbol-name name) (find-package "LISP")))
        (temp-name (gentemp)))
    `(let ((,temp-name (symbol-function ',original-name)))
       (setf (symbol-function ',name)
         #'(lambda (&rest args)
             (let (...)
               (cond ...
                     (t (apply ,temp-name args)))))))))

But you can use DEFUN instead of SETF of SYMBOL-FUNCTION, and
you can omit the temp-name if there's no possibility of name
conflicts.  That would give you:

(defmacro define-arithmetic-list-operation (name)
  (let ((original-name
          (find-symbol (symbol-name name) (find-package "LISP"))))
    `(let ((original-function (symbol-function ',original-name)))
       (defun ,name (&rest args)
         (let (...)
           (cond ...
                 (t (apply original-function args))))))))

Moreover, since you're not redefining the original-name (and remember
that it's illegal to redefine things in the LISP package), you could
just do this:

(defmacro define-arithmetic-list-operation (name)
  (let ((original-name
          (find-symbol (symbol-name name) (find-package "LISP"))))
    `(defun ,name (&rest args)
       (let (...)
         (cond ...
               (t (apply ,original-name args)))))))

> the gentemp'd symbols created in the compilation environment are
> unavailable when .o files are later loaded into a fresh lisp 

Really?  The symbols ought to exist.  What's difficult is to 
make sure they're still defined as functions.  You should not
SETF their SYMBOL-FUNCTION when expanding the macro.  Instead,
it should be done by the code in the macro expansion.
That is, don't do this at macroexpand-time:

>     (setf (symbol-function original-function-new-symbol) original-function)

> My other possible bug. It comes about when I redefine COMPLEX and
> FLOAT (to turn images into complex images and float images).  This
> turns out to break coercion of the *types* complex and float (e.g.,
> (coerce 0 'complex) fails), due to the following function in the SI
> package:
> 
> (defun known-type-p (type)
>   (when (consp type) (setq type (car type)))
>   (if (or (member type
>                   '(t nil null symbol keyword atom cons list sequence
>                     number integer bignum rational ratio float
>                     short-float single-float double-float long-float complex
>                     character standard-char string-char
>                     package stream pathname readtable hash-table random-state
>                     structure array simple-array function compiled-function))
>           (get type 'is-a-structure))
>       t
>       nil))
> 
> COERCE calls the above function (I suppose) which does not find
> IMAGE::COMPLEX symbol on the list of types (the new function COMPLEX
> is shadowing it).  This seems to me a bug in KCL.

Why?  Why should it be able to coerce to some type it doesn't know
anything about?  If you think about it again, you may find that KCL's
behavior makes sense.  That your name is "COMPLEX" should be irrelevant.
That is, IMAGE::COMPLEX should be no more meaningful that IMAGE::ZQX3.

> I had hoped some new type hackery in the IMAGE package would work:
> 
>         (deftype complex (&optional component-type)
> 	  (if (eq component-type '*)                  
> 	      `lisp::complex
> 	      `(lisp::complex (,component-type))))
> 
>         (deftype float ()
> 	  `lisp::float)
> 
> would fix it (it does interpreted), but I can't get the compiler to
> swallow it, either before the shadowed declarations (compiler goes into
> infinite loop) or after the complex and float redefinitions (compiler
> seems to misinterpret lisp::complex). Any suggestions for work arounds
> would be greatly appreciated.

My guess is that you're not arranging for the shadowing to happen in
the case where you're compiling.  It has to happen at both compile and
load times.  If instead of shadowing COMPLEX and FLOAT, I use types
MY-COMPLEX and MY-FLOAT (so that shadowing isn't an issue), it seems
to work for me.

But another problem is that it should be (COMPLEX component-type) and
not (COMPLEX (component-type)).

-- jd