Google 网上论坛不再支持新的 Usenet 帖子或订阅项。历史内容仍可供查看。

Problem creating classes from properties

已查看 2 次
跳至第一个未读帖子

Bill Clementson

未读,
2002年8月29日 00:06:002002/8/29
收件人
I am trying to dynamically create classes after reading in their
characteristics from an external file (which is similar in structure
to an ini file). However, I am having problems with the creation of
the classes when calling a defclass-builder macro from a
function. The function is meant to create any super-classes before
the passed-in class name is created. I have stripped down both the
macro and the function to just the essentials that re-create the
problem:

(defmacro defclass* (name)
`(defclass ,name () ()))

(defun create-property-class (node)
(let ((ancestor (get node 'isa)))
(if (not (null ancestor))
(create-property-class ancestor))
(defclass* node)))

To demonstrate the problem, setup 3 nodes (programmer and
person both have super-class names that are properties and
mammal is a base class with a slot called "breathes" and it
does not have a super-class):

(setf (get 'programmer 'isa) 'person)
(setf (get 'person 'isa) 'mammal)
(setf (get 'mammal 'breathes) 'air)
(setq my-node 'programmer)

In the listener, here is what happens when I try to create the
class definitions:

[16]> (defclass* programmer)
#<STANDARD-CLASS PROGRAMMER>
[17]> (create-property-class 'programmer)
#<STANDARD-CLASS NODE>
[18]> (create-property-class my-node)
#<STANDARD-CLASS NODE>

When I run the defclass* macro directly from the top level,
the class is created correctly; however, when I run the
create-property-class function it does not. I understand why
it doesn't work properly when I run the function but I don't
know how to fix the problem. I've been banging my head against
the wall all night trying different things but haven't been
able to come up with a solution. I would appreciate any
suggestions or pointers that might explain what I should be
doing.

Thanks,
--
Bill Clementson

Tim Moore

未读,
2002年8月29日 01:44:512002/8/29
收件人
On Thu, 29 Aug 2002 04:06:00 GMT, Bill Clementson <bc1...@attbi.com> wrote:
>I am trying to dynamically create classes after reading in their
>characteristics from an external file (which is similar in structure
>to an ini file). However, I am having problems with the creation of
>the classes when calling a defclass-builder macro from a
>function. The function is meant to create any super-classes before
>the passed-in class name is created. I have stripped down both the
>macro and the function to just the essentials that re-create the
>problem:
>
>(defmacro defclass* (name)
> `(defclass ,name () ()))
>
>(defun create-property-class (node)
> (let ((ancestor (get node 'isa)))
> (if (not (null ancestor))
> (create-property-class ancestor))
> (defclass* node)))

It looks like you recognize that defclass is a macro and are trying to
get around that, but your defclass* macro obviously doesn't get you
anywhere. A simple and portable way to get around this is to use
eval:

(defun create-property-class (node)
(let ((ancestor (get node 'isa)))
(if (not (null ancestor))
(create-property-class ancestor))

(eval `(defclass ,node (,ancestor) ()))))

I'm ad-libing a bit, assuming that you want ancestor as a superclass
of node. Note that you don't have to define ancestor before node as
long as ancestor is defined before any nodes are instantiated.


>When I run the defclass* macro directly from the top level,
>the class is created correctly; however, when I run the
>create-property-class function it does not. I understand why
>it doesn't work properly when I run the function but I don't
>know how to fix the problem. I've been banging my head against
>the wall all night trying different things but haven't been
>able to come up with a solution. I would appreciate any
>suggestions or pointers that might explain what I should be
>doing.

If you want to do this without evaluating defclass forms you can use
ensure-class from the metaobject protocol, if you implementation
supports it.

Tim

Fred Gilham

未读,
2002年8月29日 12:20:122002/8/29
收件人

Bill Clementson <bc1...@attbi.com> wrote:
> I am trying to dynamically create classes after reading in their
> characteristics from an external file (which is similar in structure
> to an ini file).

There is code in the AMOP book that does something that may be what
you want. I couldn't get it to work with CMUCL but it seems to work
with Allegro Common Lisp.

(I added the mop: package prefixes to the appropriate calls for ACL.
This is also necessary for CMUCL, but you have to do mop:find-class
and mop:class-name as well.)

(Anyone know why this doesn't work with CMUCL?)


(defun make-programmatic-instance (superclass-names &rest initargs)
(apply #'make-instance
(find-programmatic-class
(mapcar #'find-class superclass-names))
initargs))

(defun find-programmatic-class (superclasses)
(let ((class (find-if
#'(lambda (class)
(equal superclasses
(mop:class-direct-superclasses class)))
(mop:class-direct-subclasses (car superclasses)))))
(if class
class
(make-programmatic-class superclasses))))


(defun make-programmatic-class (superclasses)
(make-instance 'standard-class
:name (mapcar #'class-name superclasses)
:direct-superclasses superclasses
:direct-slots ()))

#|
;; Tests

(defclass shape () ())
(defclass circle (shape) ())
(defclass triangle (shape) ())
(defclass pentagon (shape) ())
(defclass color () ())
(defclass fuchsia (color) ())
(defclass orange (color) ())
(defclass magenta (color) ())
(defclass label-type () ())
(defclass top-labeled (label-type) ())
(defclass center-labeled (label-type) ())
(defclass bottom-labeled (label-type) ())

;; (defclass orange-top-labeled-circle (circle orange top-labeled) ())

(make-programmatic-instance '(circle orange top-labeled))

(setq i1 (make-programmatic-instance '(circle orange top-labeled))
i2 (make-programmatic-instance '(circle magenta bottom-labeled))
i3 (make-programmatic-instance '(circle orange top-labeled)))

(mop:class-direct-subclasses (find-class 'circle))

|#

--
Fred Gilham gil...@csl.sri.com
America does not know the difference between sex and money. It treats
sex like money because it treats sex as a medium of exchange, and it
treats money like sex because it expects its money to get pregnant and
reproduce. --- Peter Kreeft

Bill Clementson

未读,
2002年8月29日 21:44:222002/8/29
收件人
tmo...@sea-tmoore-l.dotcast.com (Tim Moore) writes:

> It looks like you recognize that defclass is a macro and are trying to
> get around that, but your defclass* macro obviously doesn't get you
> anywhere. A simple and portable way to get around this is to use
> eval:
>
> (defun create-property-class (node)
> (let ((ancestor (get node 'isa)))
> (if (not (null ancestor))
> (create-property-class ancestor))
> (eval `(defclass ,node (,ancestor) ()))))

Great! Thanks very much - that was exactly what I was after. I
really appreciate your help with this.

--
Bill Clementson

Bill Clementson

未读,
2002年8月29日 21:47:342002/8/29
收件人
Fred Gilham <gil...@snapdragon.csl.sri.com> writes:

> Bill Clementson <bc1...@attbi.com> wrote:
> > I am trying to dynamically create classes after reading in their
> > characteristics from an external file (which is similar in structure
> > to an ini file).
>
> There is code in the AMOP book that does something that may be what
> you want. I couldn't get it to work with CMUCL but it seems to work
> with Allegro Common Lisp.

Thanks for the suggestion - Tim Moore also make a suggestion in another
post which was more in line with what I was trying to do. But thank you
for considering my problem and offering an alternative.

--
Bill Clementson

Erik Naggum

未读,
2002年8月29日 21:51:002002/8/29
收件人
* Bill Clementson
| I am trying to dynamically create classes after reading in their character-

| istics from an external file (which is similar in structure to an ini file).

I suggest that you macroexpand the `defpackage´ form to see what it does.

--
Erik Naggum, Oslo, Norway

Act from reason, and failure makes you rethink and study harder.
Act from faith, and failure makes you blame someone and push harder.

Bill Clementson

未读,
2002年8月29日 23:08:352002/8/29
收件人
Erik Naggum <er...@naggum.no> writes:

> * Bill Clementson
> | I am trying to dynamically create classes after reading in their character-
> | istics from an external file (which is similar in structure to an ini file).
>
> I suggest that you macroexpand the `defpackage´ form to see what it does.

Hmmm, ok - I macroexpanded 'defpackage' and here is what I got:

[2]> (macroexpand '(defpackage mypackage (:use common-lisp) (:export "my-func")))
(EVAL-WHEN (LOAD COMPILE EVAL)
(SYSTEM::%IN-PACKAGE "MYPACKAGE" :NICKNAMES 'NIL :USE 'NIL)
(USE-PACKAGE '("COMMON-LISP") "MYPACKAGE")
(SYSTEM::INTERN-EXPORT '("my-func") "MYPACKAGE") (FIND-PACKAGE "MYPACKAGE")) ;
T

I can't see what clues this provides me with. Did you mean for me to
expand 'defclass' instead of 'defpackage'? When I expand 'defclass', I
get this:

[13]> (macroexpand '(defclass xxx (super-classes) ()))
(LET NIL
(EVAL-WHEN (COMPILE LOAD EVAL)
(CLOS::ENSURE-CLASS 'XXX :DIRECT-SUPERCLASSES
(LIST (FIND-CLASS 'SUPER-CLASSES)) :DIRECT-SLOTS (LIST)))
(FIND-CLASS 'XXX)) ;
T

This does give me some clues as it shows me that the macro 'defclass' uses
the function 'clos::ensure-class' to create the class definition. This is
what Tim Moore alluded to in his earlier email and (if I had used
'ensure-class' rather than 'defclass'), that would have been a valid
approach to get around my problem.

Did you make a typo or is there something I'm missing? If it really was
'defpackage' that you thought would be useful for me to look at,
please give me some idea as to what part of the macroexpansion relates
specifically to my problem.

Thanks,
--
Bill Clementson

Erik Naggum

未读,
2002年8月29日 23:16:222002/8/29
收件人
* Bill Clementson <bc1...@attbi.com>

| Did you mean for me to expand 'defclass' instead of 'defpackage'?

Yes. Sorry for the confusion caused by the typo/thinko.

Bill Clementson

未读,
2002年8月30日 00:33:542002/8/30
收件人
Erik Naggum <er...@naggum.no> writes:

> * Bill Clementson <bc1...@attbi.com>
> | Did you mean for me to expand 'defclass' instead of 'defpackage'?
>
> Yes. Sorry for the confusion caused by the typo/thinko.

No problem - your replies are usually so well thought out and insightful
that I kept looking for some deeper meaning that I had missed ;-)

--
Bill Clementson

Thomas A. Russ

未读,
2002年8月30日 20:31:582002/8/30
收件人

This is one of those rare cases where you really do need to use EVAL.
That is because there is no portable way of creating classes with a
function call -- the DEFCLASS macro is all you've got. You will
need something like:

(defun create-property-class (node)
(let ((ancestor (get node 'isa)))
(if (not (null ancestor))
(create-property-class ancestor))

(eval `(defclass ,node () ()))))


--
Thomas A. Russ, USC/Information Sciences Institute t...@isi.edu

0 个新帖子