22 Stimmen

Was ist die idiomatische Entsprechung von C structs in Lisp?

In Sprachen des Typs C wird von Anfang an und in jedem Einführungsbuch ein starker Schwerpunkt auf Strukturen/Rekorde und Objekte gelegt. Ihre kompletten Systeme sind dann auf die Verwaltung solcher Strukturen, ihre gegenseitigen Beziehungen und die Vererbung ausgelegt.

In der Lisp-Dokumentation findet man in der Regel 1-2 Seiten darüber, dass Lisp "auch" ein Defstrukt hat, ein einfaches Beispiel, und das war's dann auch schon. Auch die Verschachtelung von Strukturen wird überhaupt nicht erwähnt.

Für jemanden, der von einem C-Hintergrund kommt, scheint es zunächst, dass die hierarchische Organisation verschiedener Datentypen nicht die bevorzugte Methode in Lisp ist, aber abgesehen von CLOS, das ein vollwertiges Objektsystem ist und zu kompliziert, wenn Sie nur Strukturen wollen, und abgesehen von der Einpferchung alles in Listen, gibt es keinen offensichtlichen Weg, um Ihre C Struktur Wissen zu übertragen.

Welches ist die idiomatische Lisp-Methode zur hierarchischen Organisation von Daten, die den C-Strukturen am ähnlichsten ist?

--

Ich denke, die zusammenfassende Antwort auf meine Frage würde lauten: Für das Erlernen von Anfängern können defstruct und/oder plists verwendet werden, obwohl sie "Legacy Features" sind, da sie C structs am ähnlichsten sind, aber sie wurden größtenteils durch das flexiblere defclass/CLOS abgelöst, was die meisten Lisp-Programme heute verwenden.

Dies war meine erste Frage auf SO, also danke an alle, die sich die Zeit genommen haben, sie zu beantworten.

25voto

Rainer Joswig Punkte 131198

Verwenden Sie CLOS. Es ist nicht kompliziert.

Andernfalls verwenden Sie Strukturen.

Wenn Sie eine spezielle Frage zur Verwendung haben, fragen Sie einfach.

(defclass point ()
  ((x :type number)
   (y :type number)))

(defclass rectangle ()
  ((p1    :type point)
   (p2    :type point)
   (color :type color)))

Solche Dinge führen schließlich zu Schnittstellen wie Rechtecke in CLIM (der Common Lisp Interface Manager).

Geschichte

Um es noch ein wenig zu erweitern: Historisch gesehen wurden "Strukturen" in einigen Situationen auf niedriger Ebene verwendet. Strukturen haben Einzelvererbung und der Zugriff auf Slots ist "schnell". Einige Lisp-Dialekte haben mehr als das, was Common Lisp bietet. Ab Mitte der 70er Jahre wurden dann verschiedene Formen von objektorientierten Darstellungen für Lisp entwickelt. Die meisten Darstellungen von strukturierten Objekten gingen von Strukturen zu einer Art objektorientierter Lisp-Erweiterung über. Beliebt in den 80er Jahren waren klassenbasierte Systeme wie Flavors, LOOPS und andere. Auch Frame- oder Prototyp-basierte Systeme wie KEE Units oder Object Lisp waren beliebt. Das erste Macintosh Common Lisp verwendete Object Lisp für alle seine UI- und IO-Funktionen. Die MIT-Lisp-Maschine verwendete Flavors praktisch überall. Ab Mitte der 80er Jahre wurde ANSI CL entwickelt. Ein gemeinsames OO-System wurde speziell für Common Lisp entwickelt: CLOS. Es basierte auf Flavors und Loops. Während dieser Zeit wurde fast nichts getan, um Strukturen wirklich zu verbessern - abgesehen davon, dass Implementierer Wege fanden, die Implementierung zu verbessern und eine oberflächliche CLOS-Integration bereitzustellen. Zum Beispiel bieten Strukturen keine Möglichkeit, Daten zu packen. Wenn zwei Slots mit 4 Bit Inhalt vorhanden sind, gibt es keine Möglichkeit, Common Lisp anzuweisen, beide Slots in eine einzige 8-Bit-Speicherregion zu kodieren.

Als Beispiel können Sie in der Lisp Machine Manual, Kapitel über Strukturen (PDF) dass es viel komplexere Strukturen hatte als Common Lisp. Einiges davon war bereits in Maclisp in den 70er Jahren vorhanden: DEFSTRUCT im Maclisp-Handbuch .

CLOS, das Common Lisp Object System

Die meisten Menschen würden zustimmen, dass CLOS ein schönes Design ist. Manchmal führt es zu "größerem" Code, vor allem weil Bezeichner lang werden können. Aber es gibt auch CLOS-Code, wie den im AMOP-Buch, der wirklich schön geschrieben ist und zeigt, wie er verwendet werden soll.

Im Laufe der Zeit mussten sich die Implementierer mit der Herausforderung auseinandersetzen, dass die Entwickler CLOS verwenden wollten, aber auch die "Geschwindigkeit" von Strukturen haben wollten. Dies ist mit dem "vollständigen" CLOS, das das fast standardmäßige Meta Object Protocol (MOP) für CLOS enthält, noch schwieriger. Es gibt also einige Tricks, die Implementierer anbieten. In den 80er Jahren verwendete einige Software einen Schalter, so dass sie entweder mit Strukturen oder mit CLOS - CLX - kompiliert werden konnte (die Low-Level Common Lisp X11-Schnittstelle war ein Beispiel dafür). Der Grund: Auf einigen Computern und Implementierungen war CLOS viel langsamer als Strukturen. Heute wäre es unüblich, einen solchen Kompilierschalter vorzusehen.

Wenn ich mir heute eine gute Common Lisp-Implementierung ansehe, würde ich erwarten, dass sie fast überall CLOS verwendet. STREAMs sind CLOS-Klassen. CONDITIONs sind CLOS-Klassen. Das GUI-Toolkit verwendet CLOS-Klassen. Der Editor verwendet CLOS. Es könnten sogar fremde Klassen (z.B. Objective C-Klassen) in CLOS integriert werden.

In jeder Common Lisp-Implementierung, die kein Spielzeug ist, wird CLOS das Werkzeug sein, um strukturierte Daten, generisches Verhalten und eine Reihe anderer Dinge bereitzustellen.

Wie in einigen der anderen Antworten erwähnt, ist CLOS an manchen Orten möglicherweise nicht erforderlich.

Common Lisp kann mehr als einen Wert aus einer Funktion zurückgeben:

(defun calculate-coordinates (ship)
   (move-forward ship)
   (values (ship-x ship)
           (ship-y ship)))

Man kann Daten in Verschlüssen speichern:

(defun create-distance-function (ship x y)
   (lambda ()
     (point-distance (ship-x ship) (ship-y ship) x y)))

Zur Konfiguration kann man eine Art von Listen verwenden:

(defship ms-germany :initial-x 0 :initial-y 0)

Sie können darauf wetten, dass ich das Schiffsmodell in CLOS implementieren würde.

Eine Lehre aus dem Schreiben und Warten von CLOS-Software ist, dass sie sorgfältig entworfen werden muss. CLOS ist so leistungsfähig, dass man damit wirklich komplexe Software erstellen kann - eine Komplexität, die oft keine gute Idee ist. Refaktorieren und vereinfachen! Glücklicherweise sind für viele Aufgaben die grundlegenden CLOS-Funktionen ausreichend: DEFCLASS, DEFMETHOD und MAKE-INSTANCE.

Hinweise zu CLOS-Einführungen

Zunächst einmal hat Richard P. Gabriel seine CLOS-Papiere zum Herunterladen.

Siehe auch:

6voto

dmitry_vk Punkte 4291

Beispiele mit defstruct sind kurz und einfach, weil es nicht viel über sie zu sagen gibt. Cs struct s sind kompliziert:

  • Speicherverwaltung

  • kompliziertes Speicherlayout aufgrund von Unions und verschachtelten Inline-Strukturen In C, structs werden auch für andere Zwecke verwendet:

  • zum Zugriff auf den Speicher

  • aufgrund des Fehlens von Polymorphismus oder der Möglichkeit, einen Wert von "beliebigem" Typ zu übergeben: Es ist idiomatisch, einen void*

  • wegen der Unmöglichkeit, Daten auf andere Weise zu übergeben; in Lisp kann man z. B. eine Schließung übergeben, die die benötigten Daten enthält

  • aufgrund des Fehlens fortgeschrittener Aufrufkonventionen; einige Funktionen akzeptieren ihre Argumente innerhalb von Strukturen

In Common Lisp, defstruct entspricht in etwa dem von Java/C# class : Einzelvererbung, fixe Slots, können als Spezifizierer verwendet werden in defmethod s (analog zu virtual Methoden). Strukturen sind perfekt für verschachtelte Datenstrukturen geeignet.

Lisp-Programme neigen dazu, keine tief verschachtelten Strukturen zu verwenden (der Lisp-Quellcode ist die erste Ausnahme), da oft einfachere Darstellungen möglich sind.

5voto

brildum Punkte 1699

2voto

Ken Punkte 873

Ich denke, das idiomatische Äquivalent einer C-Struktur ist es, die Daten gar nicht erst in Strukturen speichern zu müssen. Ich würde sagen, dass ich bei mindestens 50% des C-ähnlichen Codes, den ich nach Lisp portiert habe, die Daten nicht in einer komplizierten Struktur speichere, sondern einfach das berechne, was ich berechnen möchte. C braucht Structs, um alles temporär zu speichern, weil seine Ausdrücke so schwach sind.

Wenn Sie ein konkretes Beispiel für C-ähnlichen Code haben, können wir Ihnen sicher einen idiomatischen Weg aufzeigen, diesen in Lisp zu implementieren.

Darüber hinaus sollten Sie bedenken, dass s-exps von Lisp son hierarchische Daten. Eine if Ausdruck in Lisp zum Beispiel sind selbst hierarchische Daten.

2voto

roscoe_casita Punkte 175
(defclass point ()
          ( x y z))

(defun distance-from-origin (point)
               (with-slots (x y z)
                   point
                 (sqrt (+ (* x x) (* y y) (* z z)))))

Ich glaube, das ist in etwa das, was ich gesucht habe, hier zu finden:

http://cl-cookbook.sourceforge.net/clos-tutorial/index.html y

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X