2013-07-09 4 views
5

Ich versuche, eine Struktur mit einigen Eigenschaften, die ich weiß, will ich, und eine beliebige Anzahl von anderen Eigenschaften, die nicht für die Grundstruktur notwendig sind zu definieren.Wie definiert man eine Struktur in Lisp mit einer beliebigen Anzahl von Argumenten?

(defstruct (node (:type list)) label [other args here]) 

weiß, dass ich in einer Funktion können Sie tun:

(defun foo (arg1 &rest args) ...) 

Gibt es irgendeine Art von &rest Äquivalent für defstruct?

Ich lerne gerade Lisp, also habe ich das Gefühl, dass mir etwas fehlt. Wenn es kein &rest Äquivalent gibt, irgendwelche Ideen, wie ich darüber gehen könnte? Danke im Voraus!

Antwort

6

Es ist nicht klar, was genau Sie suchen. Der Standardfall für Strukturen ist ein Datensatztyp mit einer festen Anzahl von Slots, von denen jeder einen Namen hat und über eine Funktion zugänglich ist, die durch das Makro defstruct generiert wird. Zum Beispiel, wenn man einmal

(defstruct node 
    label) 

getan Sie node ‚s Label mit node-label zugreifen und schnelles Nachschlagen Zeit bekommen (da es in der Regel ist nur einen Index in einen Speicher chunk). Jetzt können Sie sich dafür entscheiden, Listen als Implementierung von Strukturen zu verwenden. In diesem Fall ist node-label nur ein Alias ​​für car oder first.

(defstruct (node (:type list)) 
    label) 

CL-USER> (make-node :label 'some-label) 
(SOME-LABEL) 
CL-USER> (node-label (make-node :label 'some-label)) 
SOME-LABEL 
CL-USER> (first (make-node :label 'some-label)) 
SOME-LABEL 
CL-USER> (car (make-node :label 'some-label)) 

Wenn Sie sich für beliebige listenbasierten Schlüsselwertpaare suchen, wollen Sie wahrscheinlich eine property list, für die Common Lisp einige Komfortfunktionen enthält.

Wenn Sie eine Struktur haben möchten, die auch eine Eigenschaftsliste enthält, können Sie einen speziellen Konstruktor hinzufügen, der diese Liste auffüllt. Zum Beispiel

(defstruct (node (:type list) 
       (:constructor make-node (label &rest plist))) 
    label 
    plist) 

CL-USER> (make-node 'some-label :one 1 :two 2) 
(SOME-LABEL (:ONE 1 :TWO 2)) 
CL-USER> (node-plist (make-node 'some-label :one 1 :two 2)) 
(:ONE 1 :TWO 2) 
+0

Danke, das ist fast genau das, was ich suche. Aber gibt es eine Möglichkeit, die Eigenschaft, wie Sie es nennen, nur als andere Slots im Knoten zu haben? Mit anderen Worten, gibt es eine Möglichkeit zu tun? (Make-node 'some-label: eins 1: zwei 2) => (SOME-LABEL: ONE 1: TWO 2) ', statt' (SOME-LABEL (: EINS 1: ZWEI 2)) '? –

+1

Kurz gesagt, nein. [Rainers Antwort] (http://stackoverflow.com/a/17556349/1281433) geht im Allgemeinen auf Strukturen ein, aber der Punkt ist, dass Strukturen eine feste Anzahl von Slots haben. Obwohl Sie 'defstruct' verwenden können, um mit der Option' (: type list) ''Arrow-man's records' zu erstellen, haben Sie immer noch nur eine feste Anzahl von Slots (das heißt, die Liste hat eine feste Anzahl von Elemente). Es klingt wirklich so, als wolltest du nur eine Eigenschaftsliste. –

+0

Ja, wenn ich Rainers Antwort lese, denke ich, dass das mehr Feuerkraft ist, als ich für das brauche, was ich tue. Danke für den Rat, Jungs! –

7

In Common Lisp gelten Strukturen als starre und Low-Level-Datensätze. Sie haben keine ausgefallenen dynamischen Eigenschaften.

Was Sie mit Strukturen tun können, ist einen neuen Strukturtyp zu definieren, der von einem anderen erbt. Es gibt eine einzige Vererbung verfügbar.

Um dynamische Erweiterbarkeit zu handhaben, ist es eine typische Methode, einer Struktur einen Eigenschaftenlisten-Slot hinzuzufügen. Siehe die Antwort von Joshua.

Dann gibt es das Common Lisp Object System, das mehrere Vererbung bietet und Sie können Klassen zur Laufzeit ändern. Sie können also einer Klasse einen Slot hinzufügen und die Instanzen dieser Klasse selbst aktualisieren. Sie können auch die Klasse eines Objekts ändern und die Slots können hinzugefügt oder gelöscht werden. In der Regel haben alle Instanzen einer Klasse dieselbe Anzahl von Slots. Auch hier sieht man, dass ein Slot mit einer Eigenschaftsliste hinzugefügt und für die Erweiterbarkeit verwendet werden kann.

Es gibt andere Objektsysteme für Common Lisp, die einfach Slots auf einer Instanz pro Instanz hinzufügen können. Aber es ist normalerweise zu viel, um sie nur dafür zu verwenden, da sie ein bisschen leistungsfähiger sind.

Mit CLOS und dem Meta-Objekt-Protokoll kann man versuchen, es zu verstecken.Hier bin ich mit LispWorks:

Wir definieren eine mixin Klasse für unsere Eigenschaften:

(defclass property-mixin() 
    ((plist :initform nil)) 
    #+lispworks 
    (:optimize-slot-access nil)) 

Einstellen und Lesen der Eigenschaften:

(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)) 

Jetzt schreiben wir Methoden SLOT-VALUE akzeptieren unser Eigentum Namen zu machen :

(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))) 

Beispiel. Wir definieren ein Auto-Klasse mit zwei Steckplätze:

(defclass automobile (property-mixin) 
    ((company :initarg :company) 
    (motor :initarg :motor)) 
    #+lispworks 
    (:optimize-slot-access nil)) 

nun ein Beispiel:

CL-USER 45 > (setf a6 (make-instance 'automobile :company :audi :motor :v6)) 
#<AUTOMOBILE 402005B47B> 

Wir können einen normalen Schlitzwert erhalten:

CL-USER 46 > (slot-value c1 'motor) 
:V6 

Lassen Sie uns zu einem Schlitz schreiben, das nicht der Fall ist vorhanden, aber wird zu unserer Eigentumsliste hinzugefügt:

CL-USER 47 > (setf (slot-value a6 'seats) 4) 
4 

Wir können den Wert zurück:

CL-USER 48 > (slot-value c1 'seats) 
4 
1

dachte ich, das eher eine gesonderte Antwort wert wäre dann ein Kommentar, so hier geht:

Einige Male, wenn Sie glauben, eine Struktur oder eine brauchen Objekt, aber Sie haben einige spezielle Anforderungen, die diese Entitäten nicht erfüllen, vielleicht weil das, was Sie tatsächlich benötigten, eine andere Datenstruktur ist? Objekte oder Strukturen sind gut, wenn einige Bedingungen erfüllt sind. Eine Bedingung ist, dass die Slots statisch bekannt sind - dies ermöglicht dem Compiler, den Code besser zu verstehen, was sowohl für die Optimierung als auch für die Fehlerberichterstattung nützlich ist.

Auf der anderen Seite gibt es Datenstrukturen. Einige wurden mit der Sprachstandardbibliothek bereitgestellt, andere wurden darüber hinzugefügt. Hier ist eine Bibliothek, die viele von ihnen bietet: http://cliki.net/cl-containers aber es gibt noch mehr für spezielle Fälle.

Nun, ich werde argumentieren, dass die Verwendung einer Struktur wie Liste, Array, eine Art von Baum etc ist besser als versuchen, Objekte oder Strukturen zu erweitern, um das Hinzufügen von Slots dynamisch zu ermöglichen. Dies liegt daran, dass wir normalerweise erwarten, dass die Zeit für den Zugriff auf einen Slot vernachlässigbar ist. Das heißt, wir erwarten, dass es O (1) ist. Dies geschieht normalerweise unabhängig von der Anzahl der Slots eines Objekts. Nun, wenn Sie eine Liste darunter verwenden, machen Sie es O (n), während Sie die gleiche Semantik behalten! Sie könnten natürlich eine Hash-Tabelle verwenden, um O (1) zu machen (obwohl dies im Allgemeinen immer noch langsamer als der Slot-Zugriff ist), aber dann haben Sie ein anderes unerwartetes Verhalten, wie nil, wenn Slot nicht zurückgegeben wird Existieren statt des regulären Fehlers usw.

Ich glaube nicht, dass das Erweitern von Objekten auf diese Weise in CL üblich ist. Das ist wahrscheinlich der Grund, warum andere Antworten Sie nicht davon abhalten, das zu tun. Ich kenne weniger CL als andere Befragte, aber ich hatte eine Menge Kummer mit dieser Art von Manipulationen in einer anderen Sprache, wo dies üblich und in der Regel nicht erwünscht ist.

Verwandte Themen