W Common Lisp struktury są traktowane jako zapisy sztywne i niskiego poziomu. Nie mają fantazyjnych dynamicznych funkcji.
To, co można zrobić ze strukturami, to określenie nowego typu struktury, która dziedziczy po innej. Dostępne jest pojedyncze dziedziczenie.
Aby poradzić sobie z dynamiczną rozszerzalnością, typowym sposobem jest dodanie szczeliny listy właściwości do struktury. Zobacz odpowiedź Jozuego.
Następnie istnieje system Common Lisp Object, który zapewnia wielokrotne dziedziczenie i można zmieniać klasy w czasie wykonywania. Możesz więc dodać slot do klasy i same wystąpienia tej klasy. Możesz także zmienić klasę obiektu i gniazda mogą zostać dodane lub usunięte. Jednak zazwyczaj wszystkie wystąpienia klasy będą miały ten sam zestaw gniazd. Ponownie widzi się, że slot z listą właściwości można dodać i wykorzystać do rozszerzenia.
Istnieją inne systemy obiektowe dla Common Lisp, które mogą z łatwością dodawać gniazda w bazie dla każdej instancji. Ale zwykle jest ich za dużo, aby używać ich tylko do tego, ponieważ są one nieco mocniejsze.
Dzięki CLOS i protokołowi Meta-obiektu można spróbować go ukryć.Tutaj używam LispWorks:
Definiujemy wstawką klasę dla naszych nieruchomości:
(defclass property-mixin()
((plist :initform nil))
#+lispworks
(:optimize-slot-access nil))
ustawienie i odczyt właściwości:
(defmethod set-property ((object property-mixin) key value)
(setf (getf (slot-value object 'plist) key) value))
(defmethod get-property ((object property-mixin) key)
(getf (slot-value object 'plist) key))
Teraz piszemy metod, aby SLOT-VALUE
akceptując nasze imiona własności :
(defmethod (setf clos:slot-value-using-class)
(value (class standard-class) (object property-mixin) slot-name)
(declare (ignorable class))
(if (slot-exists-p object slot-name)
(call-next-method)
(progn
(set-property object slot-name value)
value)))
(defmethod clos:slot-value-using-class ((class standard-class)
(object property-mixin)
slot-name)
(declare (ignorable class))
(if (slot-exists-p object slot-name)
(call-next-method)
(get-property object slot-name)))
Przykład. Definiujemy klasę samochodowy z dwoma gniazdami:
(defclass automobile (property-mixin)
((company :initarg :company)
(motor :initarg :motor))
#+lispworks
(:optimize-slot-access nil))
obecnie przykład:
CL-USER 45 > (setf a6 (make-instance 'automobile :company :audi :motor :v6))
#<AUTOMOBILE 402005B47B>
Możemy dostać normalną wartość gniazd:
CL-USER 46 > (slot-value c1 'motor)
:V6
Napiszmy do gniazda, które nie istnieje, ale zostanie dodany do naszej listy nieruchomości:
CL-USER 47 > (setf (slot-value a6 'seats) 4)
4
możemy uzyskać wartość z powrotem:
CL-USER 48 > (slot-value c1 'seats)
4
Dzięki, prawie dokładnie to, czego szukam. Ale czy istnieje jakiś sposób, aby mieć listę właściwości, jak to ujęłeś, jako tylko inne gniazda w 'węźle'? Innymi słowy, czy istnieje sposób zrobienia '(make-node 'some-label: one 1: two 2) => (SOME-LABEL: ONE 1: TWO 2)', zamiast '(SOME-LABEL (: ONE 1: TWO 2)) '? –
W skrócie, nie. [Odpowiedź Rainera] (http://stackoverflow.com/a/17556349/1281433) idzie głębiej o struktury w ogóle, ale chodzi o to, że struktury mają ustaloną liczbę slotów. Nawet jeśli możesz użyć 'defstruct' do utworzenia" rekordów biednych ludzi "za pomocą opcji' (: type list) ', nadal będziesz mieć stałą liczbę slotów (co oznacza, że lista ma ustaloną liczbę elementy). To naprawdę brzmi, jakbyś chciał tylko listę nieruchomości. –
Tak, czytając odpowiedź Rainera, myślę, że to jest więcej siły ognia, niż potrzebuję do tego, co robię. Dzięki za radę, chłopaki! –