Wie schreibt man ähnliche Funktionen in Common Lisp?

8

Ich lerne Common Lisp von Practical Common Lisp . Es gibt ein Beispiel für Hilfsfunktionen zum Lesen und Schreiben von Binärdateien in Kapitel 24. Hier ein Beispiel:

%Vor%

Ich kann auch Funktionen schreiben, um andere Arten von Binärzahlen zu lesen. Aber ich dachte, dass dies das DRY-Prinzip verletzt. Außerdem werden diese Funktionen ähnlich sein, also habe ich versucht, die Funktionen mit Makros zu erzeugen.

%Vor%

Es funktioniert. Es erzeugt Funktionen zum Lesen und Schreiben von vorzeichenlosen und vorzeichenbehafteten Ganzzahlen in den Größen 1, 2, 4 und 8. SLIME versteht es. Aber ich frage mich, ob es bessere Möglichkeiten gibt.

Was ist der beste Weg, um eine Reihe ähnlicher Funktionen in Common Lisp zu schreiben?

    
nisekgao 01.01.2017, 11:00
quelle

2 Antworten

9

Es gibt einige Probleme mit diesem Code, obwohl der generelle Ansatz, Makros zu erzeugen, in Ordnung ist.

Benennung

Die Makros sollten nicht make-... heißen, weil sie keine Funktionen sind, die etwas ausmachen, sondern Makros, die eine Funktion definieren.

Codegenerierung

Der EVAL-WHEN ... EVAL Code ist wirklich schlecht und sollte nicht auf diese Weise verwendet werden.

Der bessere Weg ist das Schreiben eines Makros, das mit den Funktionsdefinitionen in ein progn expandiert.

Wenn ich EVAL verwenden möchte, müsste ich keine Code-generierenden Makros schreiben, sondern nur Code-Generierungsfunktionen. Aber ich möchte nicht EVAL verwenden, ich möchte direkt Code für den Compiler erstellen. Wenn ich code-generierende Makros habe, brauche ich nicht EVAL .

EVAL ist keine gute Idee, weil es nicht klar ist, dass der Code kompiliert werden würde - was von der Implementierung abhängig wäre. Auch die Auswertung würde zur Kompilier- und Ladezeit stattfinden. Es wäre besser, die Funktionen zur Kompilierzeit zu kompilieren und sie nur zur Ladezeit zu laden. Ein Dateicompiler könnte auch mögliche Optimierungen für die ausgewerteten Funktionen übersehen.

%Vor%

Anstelle von EVAL-WHEN ... EVAL definieren wir ein anderes Makro und verwenden es später:

%Vor%

Jetzt können wir das obige Makro verwenden, um alle Funktionen zu generieren:

%Vor%

Sie können die Erweiterung hier sehen:

%Vor%

Jedes Unterformular wird dann zu den Funktionsdefinitionen erweitert.

Auf diese Weise führt der Compiler die Makros aus, um den gesamten Code zur Kompilierzeit zu generieren, und der Compiler kann dann Code für alle Funktionen generieren.

Effizienz / Standardwerte

In einer Funktion der niedrigsten Ebene möchte ich möglicherweise keinen Parameter &optional verwenden. Der Standardaufruf würde den Wert einer dynamischen Bindung erhalten, und schlimmer noch, *standard-input* / *standard-output* ist möglicherweise kein Stream, für den READ-BYTE oder WRITE-BYTE funktioniert. Nicht in jeder Implementierung können Sie einen Standard-Input / Output-Stream als binären Stream verwenden.

LispWorks:

%Vor%

Ich möchte auch erklären, dass alle generierten Funktionen inline sind.

Typdeklarationen wären eine andere Sache, über die man nachdenken sollte.

Zusammenfassung : Verwenden Sie nicht EVAL.

    
Rainer Joswig 01.01.2017, 11:47
quelle
2

Im Allgemeinen würde ich es vorziehen, einfach die Anzahl der zu lesenden Bytes als einen anderen Parameter zu der Funktion hinzuzufügen:

%Vor%

Signedness und Endianness können als Schlüsselwortargumente hinzugefügt werden. Diese Art der Programmierung ist gut für verständlichen Code, der auch durch Tools wie SLIME leicht navigiert werden kann.

Das Abrollen durch Makros ist eine gültige Optimierungsstrategie, und ich verzichte darauf Rainers Antwort .

Im konkreten Fall des Lesens von Zahlen aus einem Datenstrom ist die Optimierung wahrscheinlich von Anfang an ein gültiges Ziel, da dies in engen Schleifen häufig verwendet wird.

Wenn Sie dies tun, sollten Sie jedoch gründlich dokumentieren, was generiert wird. Wenn ein Leser des Codes einen Operator read8bes sieht, kann er nicht leicht herausfinden, wo er definiert wurde. Du musst ihm helfen.

    
Svante 03.01.2017 23:45
quelle

Tags und Links