I have a really simple class that is repetitive:
(defpclass book ()
((title :accessor title :initarg "" :index t)
(author :accessor author :initarg "" :index t)
...))
I've created a macro so I don't have to do that, and so it's easier to
add fields later:
(defmacro book-macro (fields)
`(defpclass book ()
,(let ((params ()))
(dolist (field fields)
(push `(,field :accessor ,field :initarg "" :index t) params))
params)))
When I expand the macro, it works how I would like: (macroexpand-1
'(book-macro (title author isbn)))
(DEFPCLASS BOOK NIL
(ISBN :ACCESSOR ISBN :INITARG "" :INDEX T)
(AUTHOR :ACCESSOR AUTHOR :INITARG "" :INDEX T)
(TITLE :ACCESSOR TITLE :INITARG "" :INDEX T)))
So the problem is, when I load the file that contains this class, I
can't get it to define this class so I can make an instance of a
book. Any ideas? I'm a total Lisp newbie, so forgive me if this is a
stupid question.
Thanks
Scott
sycoogtit <·········@gmail.com> writes:
> I have a really simple class that is repetitive:
>
> (defpclass book ()
> ((title :accessor title :initarg "" :index t)
> (author :accessor author :initarg "" :index t)
> ...))
Um, I don't recognize "defPclass", so I'm not quite sure what sort of
syntax you need to come up with.
> I've created a macro so I don't have to do that, and so it's easier to
> add fields later:
>
> (defmacro book-macro (fields)
> `(defpclass book ()
> ,(let ((params ()))
> (dolist (field fields)
> (push `(,field :accessor ,field :initarg "" :index t) params))
> params)))
Personal style note: I would tend to put the LET binding of params and
the DOLIST outside of the expansion and just include the expansion
itself inside the backquote. But that's clearly just a style issue.
Another style note: This would probably be a good macro to call DEFBOOK
or DEF-BOOK, since it creates definitions.
You might also want to make this macro a LOT more general by taking a
NAME parameter as well, to use as the name of the class. That way you
won't need a separate macro for magazines, etc. Not sure if you want to
have an option for including the superclasses as well. Perhaps
something like:
(defmacro def-myclass (name supers fields)
(let ((slots ()))
(dolist (field fields)
(push `(,field :accessor ,field :initarg "" :index t)
slots))
`(defpclass ,name ,supers
,slots)))
>
> When I expand the macro, it works how I would like: (macroexpand-1
> '(book-macro (title author isbn)))
>
> (DEFPCLASS BOOK NIL
> (ISBN :ACCESSOR ISBN :INITARG "" :INDEX T)
> (AUTHOR :ACCESSOR AUTHOR :INITARG "" :INDEX T)
> (TITLE :ACCESSOR TITLE :INITARG "" :INDEX T)))
Um, something's wrong here. It seems that a parenthesis is missing at
the start of your slots. I'm assuming it went missing during the
cut-and-paste.
> So the problem is, when I load the file that contains this class, I
> can't get it to define this class so I can make an instance of a
> book. Any ideas? I'm a total Lisp newbie, so forgive me if this is a
> stupid question.
Hmmm. A couple more questions, then:
1. Do you get any error messages while loading the file?
2. Is BOOK-MACRO defined before it is used?
3. What about DEFPCLASS?
4. I presume that (find-class 'book) returns NIL?
5. What happens when you try to create an instance?
--
Thomas A. Russ, USC/Information Sciences Institute
sycoogtit wrote:
> I have a really simple class that is repetitive:
>
> (defpclass book ()
> ((title :accessor title :initarg "" :index t)
> (author :accessor author :initarg "" :index t)
> ...))
>
> I've created a macro so I don't have to do that, and so it's easier to
> add fields later:
>
> (defmacro book-macro (fields)
> `(defpclass book ()
> ,(let ((params ()))
> (dolist (field fields)
> (push `(,field :accessor ,field :initarg "" :index t) params))
> params)))
>
> When I expand the macro, it works how I would like: (macroexpand-1
> '(book-macro (title author isbn)))
>
> (DEFPCLASS BOOK NIL
> (ISBN :ACCESSOR ISBN :INITARG "" :INDEX T)
> (AUTHOR :ACCESSOR AUTHOR :INITARG "" :INDEX T)
> (TITLE :ACCESSOR TITLE :INITARG "" :INDEX T)))
>
> So the problem is, when I load the file that contains this class, I
> can't get it to define this class so I can make an instance of a
> book. Any ideas? I'm a total Lisp newbie, so forgive me if this is a
> stupid question.
Well, your big mistake is a crappy problem description. :)
What the hell is defpclass?
What error do you get?
Are you sure the list of slots should not be in its own list (ie, I
would expect defpclass to ape the syntax of defclass and want:
(defpclass book nil
( ; start slot list
(isbn ..etc)
(title ....)
) ; end slot list
) ; end defpclass
Not that we use that C-style for handling {}s, just so you see what I am
suggesting.
kt
--
$$$$$: http://www.theoryyalgebra.com/
Cells: http://common-lisp.net/project/cells/
BSlog: http://smuglispweeny.blogspot.com/
sycoogtit <·········@gmail.com> writes:
> I have a really simple class that is repetitive:
>
> (defpclass book ()
> ((title :accessor title :initarg "" :index t)
> (author :accessor author :initarg "" :index t)
> ...))
>
> I've created a macro so I don't have to do that, and so it's easier to
> add fields later:
>
> (defmacro book-macro (fields)
> `(defpclass book ()
> ,(let ((params ()))
> (dolist (field fields)
> (push `(,field :accessor ,field :initarg "" :index t) params))
> params)))
>
> When I expand the macro, it works how I would like: (macroexpand-1
> '(book-macro (title author isbn)))
>
> (DEFPCLASS BOOK NIL
> (ISBN :ACCESSOR ISBN :INITARG "" :INDEX T)
> (AUTHOR :ACCESSOR AUTHOR :INITARG "" :INDEX T)
> (TITLE :ACCESSOR TITLE :INITARG "" :INDEX T)))
>
> So the problem is, when I load the file that contains this class, I
> can't get it to define this class so I can make an instance of a
> book. Any ideas? I'm a total Lisp newbie, so forgive me if this is a
> stupid question.
Usually, :initarg is given a keyword that is used to specify the
initial argument for the slot. Perhaps defpclass doesn't accept a
string here?
Otherwise, given that defpclass is not defined in COMMON-LISP, you
must of course ensure that it is defined before you used it from your
book macro.
You should try to generalize it. A book macro is totally useless (but
perhaps to define a book class, but a book in the universe is
insignificant). So, let's do rather a DEFINE-QUICK-CLASS macro:
C/USER[8]> (defmacro define-quick-class (classname fields)
`(defclass ,classname ()
,(let ((params ()))
(dolist (field fields params)
(push `(,field :accessor ,field :initarg ,(intern (string field) #.(find-package "KEYWORD")))
params)))))
DEFINE-QUICK-CLASS
C/USER[9]> (macroexpand-1 '(define-quick-class book (title author isbn)))
(DEFCLASS BOOK NIL ((ISBN :ACCESSOR ISBN :INITARG :ISBN) (AUTHOR :ACCESSOR AUTHOR :INITARG :AUTHOR) (TITLE :ACCESSOR TITLE :INITARG :TITLE))) ;
T
C/USER[10]> (define-quick-class book (title author isbn))
#1=#<STANDARD-CLASS BOOK>
C/USER[11]> (inspect (make-instance 'book :title "Practical Common Lisp" :author "Peter Seibel" :isbn "1590592395"))
#<COMMON-LISP-USER::BOOK #x207C0816>: standard object
type: COMMON-LISP-USER::BOOK
0 [ISBN]: "1590592395"
1 [AUTHOR]: "Peter Seibel"
2 [TITLE]: "Practical Common Lisp"
INSPECT-- type :h for help; :q to return to the REPL ---> :q
C/USER[12]>
--
__Pascal Bourguignon__ http://www.informatimago.com/
"Our users will know fear and cower before our software! Ship it!
Ship it and let them flee like the dogs they are!"
Wow, there are a bunch of great replies here. I really appreciate so
much help in so little time! I'll answer each reply.
On Aug 12, 6:03 pm, Kenny <·········@gmail.com> wrote:
>
> What the hell is defpclass?
Sorry, I should have been more informative about that. defpclass is
from the Elephant (http://common-lisp.net/project/elephant/)
Database... library? It takes the same (I think) parameters as
depclass.
>
> What error do you get?
There is no class named BOOK.
>
> Are you sure the list of slots should not be in its own list (ie, I
> would expect defpclass to ape the syntax of defclass and want:
>
> (defpclass book nil
> ( ; start slot list
> (isbn ..etc)
> (title ....)
> ) ; end slot list
> ) ; end defpclass
>
I actually lost a parenthesis in my copy-paste, so it does get
expanded into what you've suggested.
On Aug 12, 6:05 pm, ····@sevak.isi.edu (Thomas A. Russ) wrote:
>
> Personal style note: I would tend to put the LET binding of params and
> the DOLIST outside of the expansion and just include the expansion
> itself inside the backquote. But that's clearly just a style issue.
>
> Another style note: This would probably be a good macro to call DEFBOOK
> or DEF-BOOK, since it creates definitions.
>
> You might also want to make this macro a LOT more general by taking a
> NAME parameter as well, to use as the name of the class. That way you
> won't need a separate macro for magazines, etc. Not sure if you want to
> have an option for including the superclasses as well. Perhaps
> something like:
>
> (defmacro def-myclass (name supers fields)
> (let ((slots ()))
> (dolist (field fields)
> (push `(,field :accessor ,field :initarg "" :index t)
> slots))
> `(defpclass ,name ,supers
> ,slots)))
>
>
That is much better. Thanks for the style tips! I clearly need them!
> > (DEFPCLASS BOOK NIL
> > (ISBN :ACCESSOR ISBN :INITARG "" :INDEX T)
> > (AUTHOR :ACCESSOR AUTHOR :INITARG "" :INDEX T)
> > (TITLE :ACCESSOR TITLE :INITARG "" :INDEX T)))
>
> Um, something's wrong here. It seems that a parenthesis is missing at
> the start of your slots. I'm assuming it went missing during the
> cut-and-paste.
Yes, you're right. There's another parenthesis before ISBN.
>
> Hmmm. A couple more questions, then:
>
> 1. Do you get any error messages while loading the file?
No errors or warnings.
> 2. Is BOOK-MACRO defined before it is used?
> 3. What about DEFPCLASS?
Well, I'm not sure I'm "using" it correctly. I do:
(defpclass book-macro ...)
(macroexpand-1 '(book-macro ...))
I was hoping that the expansion would magically include that
definition, but I guess it isn't.
> 4. I presume that (find-class 'book) returns NIL?
Hm. (find-class 'book) returns an error:
There is no class named BOOK.
> 5. What happens when you try to create an instance?
Same as above.
On Aug 12, 7:18 pm, ····@informatimago.com (Pascal J. Bourguignon)
wrote:
> Usually, :initarg is given a keyword that is used to specify the
> initial argument for the slot. Perhaps defpclass doesn't accept a
> string here?
>
> Otherwise, given that defpclass is not defined in COMMON-LISP, you
> must of course ensure that it is defined before you used it from your
> book macro.
Ah-hah. Indeed, :initarg does not accept a string. I just removed
that part from the macro, but it still doesn't magically load.
However, I can copy-paste the expansion into REPL and the class is
then defined.
>
> You should try to generalize it. A book macro is totally useless (but
> perhaps to define a book class, but a book in the universe is
> insignificant). So, let's do rather a DEFINE-QUICK-CLASS macro:
>
> C/USER[8]> (defmacro define-quick-class (classname fields)
> `(defclass ,classname ()
> ,(let ((params ()))
> (dolist (field fields params)
> (push `(,field :accessor ,field :initarg ,(intern (string field) #.(find-package "KEYWORD")))
> params)))))
> DEFINE-QUICK-CLASS
> C/USER[9]> (macroexpand-1 '(define-quick-class book (title author isbn)))
> (DEFCLASS BOOK NIL ((ISBN :ACCESSOR ISBN :INITARG :ISBN) (AUTHOR :ACCESSOR AUTHOR :INITARG :AUTHOR) (TITLE :ACCESSOR TITLE :INITARG :TITLE))) ;
> T
> C/USER[10]> (define-quick-class book (title author isbn))
> #1=#<STANDARD-CLASS BOOK>
> C/USER[11]> (inspect (make-instance 'book :title "Practical Common Lisp" :author "Peter Seibel" :isbn "1590592395"))
Ah-hah! That's it! I expanded the macro and then thought I could
just make an instance. Once I added (book-macro (title author isbn)),
it all worked!
Thanks again everyone for all your help!
Scott
sycoogtit wrote:
> Wow, there are a bunch of great replies here. I really appreciate so
> much help in so little time! I'll answer each reply.
>
> On Aug 12, 6:03 pm, Kenny <·········@gmail.com> wrote:
>> What the hell is defpclass?
>
> Sorry, I should have been more informative about that. defpclass is
> from the Elephant (http://common-lisp.net/project/elephant/)
> Database... library? It takes the same (I think) parameters as
> depclass.
>
>> What error do you get?
>
> There is no class named BOOK.
>
>> Are you sure the list of slots should not be in its own list (ie, I
>> would expect defpclass to ape the syntax of defclass and want:
>>
>> (defpclass book nil
>> ( ; start slot list
>> (isbn ..etc)
>> (title ....)
>> ) ; end slot list
>> ) ; end defpclass
>>
>
> I actually lost a parenthesis in my copy-paste, so it does get
> expanded into what you've suggested.
>
>
> On Aug 12, 6:05 pm, ····@sevak.isi.edu (Thomas A. Russ) wrote:
>> Personal style note: I would tend to put the LET binding of params and
>> the DOLIST outside of the expansion and just include the expansion
>> itself inside the backquote. But that's clearly just a style issue.
>>
>> Another style note: This would probably be a good macro to call DEFBOOK
>> or DEF-BOOK, since it creates definitions.
>>
>> You might also want to make this macro a LOT more general by taking a
>> NAME parameter as well, to use as the name of the class. That way you
>> won't need a separate macro for magazines, etc. Not sure if you want to
>> have an option for including the superclasses as well. Perhaps
>> something like:
>>
>> (defmacro def-myclass (name supers fields)
>> (let ((slots ()))
>> (dolist (field fields)
>> (push `(,field :accessor ,field :initarg "" :index t)
>> slots))
>> `(defpclass ,name ,supers
>> ,slots)))
>>
>>
>
> That is much better. Thanks for the style tips! I clearly need them!
>
>>> (DEFPCLASS BOOK NIL
>>> (ISBN :ACCESSOR ISBN :INITARG "" :INDEX T)
>>> (AUTHOR :ACCESSOR AUTHOR :INITARG "" :INDEX T)
>>> (TITLE :ACCESSOR TITLE :INITARG "" :INDEX T)))
>> Um, something's wrong here. It seems that a parenthesis is missing at
>> the start of your slots. I'm assuming it went missing during the
>> cut-and-paste.
>
> Yes, you're right. There's another parenthesis before ISBN.
>
>> Hmmm. A couple more questions, then:
>>
>> 1. Do you get any error messages while loading the file?
>
> No errors or warnings.
>
>> 2. Is BOOK-MACRO defined before it is used?
>> 3. What about DEFPCLASS?
>
> Well, I'm not sure I'm "using" it correctly. I do:
> (defpclass book-macro ...)
> (macroexpand-1 '(book-macro ...))
>
> I was hoping that the expansion would magically include that
> definition, but I guess it isn't.
>
>> 4. I presume that (find-class 'book) returns NIL?
>
> Hm. (find-class 'book) returns an error:
> There is no class named BOOK.
Find-class, btw, also takes a (first) optional argument, errorp.
>
>> 5. What happens when you try to create an instance?
>
> Same as above.
>
>
> On Aug 12, 7:18 pm, ····@informatimago.com (Pascal J. Bourguignon)
> wrote:
>
>> Usually, :initarg is given a keyword that is used to specify the
>> initial argument for the slot. Perhaps defpclass doesn't accept a
>> string here?
>>
>> Otherwise, given that defpclass is not defined in COMMON-LISP, you
>> must of course ensure that it is defined before you used it from your
>> book macro.
>
> Ah-hah. Indeed, :initarg does not accept a string. I just removed
> that part from the macro, but it still doesn't magically load.
> However, I can copy-paste the expansion into REPL and the class is
> then defined.
>
>> You should try to generalize it. A book macro is totally useless (but
>> perhaps to define a book class, but a book in the universe is
>> insignificant). So, let's do rather a DEFINE-QUICK-CLASS macro:
>>
>> C/USER[8]> (defmacro define-quick-class (classname fields)
>> `(defclass ,classname ()
>> ,(let ((params ()))
>> (dolist (field fields params)
>> (push `(,field :accessor ,field :initarg ,(intern (string field) #.(find-package "KEYWORD")))
>> params)))))
>> DEFINE-QUICK-CLASS
>> C/USER[9]> (macroexpand-1 '(define-quick-class book (title author isbn)))
>> (DEFCLASS BOOK NIL ((ISBN :ACCESSOR ISBN :INITARG :ISBN) (AUTHOR :ACCESSOR AUTHOR :INITARG :AUTHOR) (TITLE :ACCESSOR TITLE :INITARG :TITLE))) ;
>> T
>> C/USER[10]> (define-quick-class book (title author isbn))
>> #1=#<STANDARD-CLASS BOOK>
>> C/USER[11]> (inspect (make-instance 'book :title "Practical Common Lisp" :author "Peter Seibel" :isbn "1590592395"))
>
> Ah-hah! That's it! I expanded the macro and then thought I could
> just make an instance. Once I added (book-macro (title author isbn)),
> it all worked!
>
> Thanks again everyone for all your help!
> Scott
We are soooo slipping. There was a day when the OP would at this point
be no more than a bloody carcass left for the jackals and vultures. Not
sure the CLHS specifies in which order.
<sigh>
kenny
--
$$$$$: http://www.theoryyalgebra.com/
Cells: http://common-lisp.net/project/cells/
BSlog: http://smuglispweeny.blogspot.com/
Kenny wrote:
> We are soooo slipping. There was a day when the OP would at this point
> be no more than a bloody carcass left for the jackals and vultures. Not
> sure the CLHS specifies in which order.
>
> <sigh>
Chalk it up to the end of summer. I'm sure you'll return to form soon
enough.
- Daniel