Prev: Comparing Lisp to Python, what you consider more important:speed or macros.
Next: Rephrasing an English statement into questions.
From: Pascal J. Bourguignon on 5 May 2010 02:58 Jonathan Braud <jonathan.braud.NOSPAMTHANKYOUVERYMUCH+usenet(a)gmail.com> writes: > Thanks to the three of you. I guess it was high time I read a few things > on how the reader actually reads! > > The solution Thomas gave appears to work. > > It's the way to do it that feels the most natural to me. Still, I tried > to find one that involved read-time evaluation, and the only thing I > could come up with was calling the macro like this: > > (defstruct-shadow-expand #.(progn (shadow 'lambda) 'lambda) ...) > > It obviously makes the macro quite inconvenient to use. So I'm wondering > if you were thinking of something more clever. Although, unless I missed > something again, I really don't see how a macro could have any impact on > what happens at read time. Actually, there is an even simplier solution: (eval-when (:compile-toplevel :load-toplevel :execute) (shadow 'lambda)) (defstruct-export lambda slot) Assuming: (eval-when (:compile-toplevel :load-toplevel :execute) (defun sconcat (&rest args) (intern (format nil "~{~A~}" args)))) (defmacro defstruct-export (name &rest slots) `(PROGN (DEFSTRUCT ,name ,slots) ,@(mapcar (lambda (sym) `(EXPORT ',sym)) (cons (sconcat 'make- name) (mapcar (lambda (slot) (sconcat name '- slot)) slots))))) (macroexpand '(defstruct-export lambda slot)) --> (PROGN (DEFSTRUCT LAMBDA (SLOT)) (EXPORT 'MAKE-LAMBDA) (EXPORT 'LAMBDA-SLOT)) The point is to realize that both the REPL, LOAD, and COMPILE-FILE interspece reading with (evaluating and printing) or compiling (at least compile-time side-effects evaluation). When you give to the REPL, or when you compile a file containing: (eval-when (:compile-toplevel :load-toplevel :execute) (shadow 'lambda)) (defstruct-export lambda slot) 1. (eval-when (:compile-toplevel :load-toplevel :execute) (shadow 'lambda)) is read. the symbol in the quote form is CL:LAMBDA, with the right assumptions. 2. (eval-when (:compile-toplevel :load-toplevel :execute) (shadow 'lambda)) is evaluated. CL:LAMBDA is no more accessible from *PACKAGE*. 3. (defstruct-export lambda slot) is read. The second symbol is a new symbol named "LAMBDA" interned in *PACKAGE*. 4. (defstruct-export lambda slot) is macroexpanded (in the REPL or LOAD) or mininal-compiled (in COMPILE-FILE). 5. (PROGN (DEFSTRUCT LAMBDA (SLOT)) (EXPORT 'MAKE-LAMBDA) (EXPORT 'LAMBDA-SLOT)) is executed (in the REPL or LOAD) or compiled (in COMPPILE-FILE). Since LAMBDA is not CL:LAMBDA, everything goes well. There's even a simplier way, which is to put "LAMBDA" in the :shadow list of the defpackage form for the package where this lambda structure is defined: (defpackage "EXAMPLE" (:use "CL") (:shadow "LAMBDA")) (in-package "EXAMPLE") (defstruct-export lambda slot) ;; Do not fight the CL way! -- __Pascal Bourguignon__
From: Jonathan Braud on 5 May 2010 05:03 In article <878w7yq1fx.fsf(a)galatea.lan.informatimago.com>, pjb(a)informatimago.com (Pascal J. Bourguignon) wrote: > Actually, there is an even simplier solution: > > (eval-when (:compile-toplevel :load-toplevel :execute) > (shadow 'lambda)) > (defstruct-export lambda slot) > But this works only because (eval-when ... (shadow 'lambda)) is evaluated before (defstruct-export lambda slot) is even read, right? If I tried to put it in a macro, I would get the same problem I had in the first post. > There's even a simplier way, which is to put "LAMBDA" in the :shadow > list of the defpackage form for the package where this lambda structure > is defined: > > (defpackage "EXAMPLE" > (:use "CL") > (:shadow "LAMBDA")) > > (in-package "EXAMPLE") > > (defstruct-export lambda slot) > Yes, except the original purpose was to let a macro take care of all that. Using the shadow list is just cheating :-).
From: Thomas A. Russ on 5 May 2010 14:49 Jonathan Braud <jonathan.braud.NOSPAMTHANKYOUVERYMUCH+usenet(a)gmail.com> writes: > In article <878w7yq1fx.fsf(a)galatea.lan.informatimago.com>, > pjb(a)informatimago.com (Pascal J. Bourguignon) wrote: > > > Actually, there is an even simplier solution: > > > > (eval-when (:compile-toplevel :load-toplevel :execute) > > (shadow 'lambda)) > > (defstruct-export lambda slot) > > > > But this works only because (eval-when ... (shadow 'lambda)) is > evaluated before (defstruct-export lambda slot) is even read, right? > If I tried to put it in a macro, I would get the same problem I had in > the first post. Correct. -- Thomas A. Russ, USC/Information Sciences Institute
From: Pascal J. Bourguignon on 7 May 2010 20:14
Jonathan Braud <jonathan.braud.NOSPAMTHANKYOUVERYMUCH+usenet(a)gmail.com> writes: > In article <878w7yq1fx.fsf(a)galatea.lan.informatimago.com>, > pjb(a)informatimago.com (Pascal J. Bourguignon) wrote: > >> Actually, there is an even simplier solution: >> >> (eval-when (:compile-toplevel :load-toplevel :execute) >> (shadow 'lambda)) >> (defstruct-export lambda slot) >> > > But this works only because (eval-when ... (shadow 'lambda)) is > evaluated before (defstruct-export lambda slot) is even read, right? > If I tried to put it in a macro, I would get the same problem I had in > the first post. > >> There's even a simplier way, which is to put "LAMBDA" in the :shadow >> list of the defpackage form for the package where this lambda structure >> is defined: >> >> (defpackage "EXAMPLE" >> (:use "CL") >> (:shadow "LAMBDA")) >> >> (in-package "EXAMPLE") >> >> (defstruct-export lambda slot) >> > > Yes, except the original purpose was to let a macro take care of all > that. Using the shadow list is just cheating :-). Well, since you insist to get the rope, here it is. You can do it at run-time. (You could do it at macroexpansion time but it would be meaningless, since you don't control when this occurs). (eval-when (:compile-toplevel :load-toplevel :execute) (defun strcat (&rest args) (format nil "~{~A~}" args))) (defmacro defstruct-export (name &rest slots) `(PROGN (shadow ',name) (eval `(DEFSTRUCT ,(intern ,(string name)) ,',@slots)) (export (mapcar (function intern) ',(cons (strcat 'make- name) (mapcar (lambda (slot) (strcat name '- slot)) slots)))) (values))) ; it would be quite purposeless to return ',name like other def* macros. (macroexpand-1 '(defstruct-export lambda slot-1 slot-2)) --> (PROGN (SHADOW 'LAMBDA) (EVAL (CONS 'DEFSTRUCT (CONS (INTERN "LAMBDA") '(SLOT-1 SLOT-2)))) (EXPORT (MAPCAR #'INTERN '("MAKE-LAMBDA" "LAMBDA-SLOT-1" "LAMBDA-SLOT-2"))) (VALUES)) ; T The problem of this, is that the shadowing is done at run-time, therefore the code that is read after a call to defstruct-export will still intern the old symbol, which will be shadowed. Now, you would have to load the source in two step: one little part containing the defstruct-export form, which can be loaded and compiled at compilation time, and another with the rest of the code, which must be loaded (and possibly compiled) at run-time. And if you try to do it at macro expansion time, then you will just lost control over when the shadowing occurs so you won't be in a better situation. -- __Pascal Bourguignon__ http://www.informatimago.com |