2016-11-14 4 views
1

Der folgende Code implementiert einen Makroaufruf mit einem impliziten optionalen Parameter - implizit, da er im & Restparameter eingebettet ist. Gibt es eine bessere Möglichkeit, das Makro (und seine unterstützende Funktion) zu codieren - vielleicht indem der optionale Parameter explizit mit einem optionalen Schlüsselwort & (oder auf eine andere Weise) angegeben wird? Es ist bevorzugt, dass der erste Parameter erforderlich ist, der zweite optional ist und die zahlreichen verbleibenden Parameter erforderlich sind. Auch bevorzugt die Makrodefinition einfach, mit der Arbeit durch die unterstützende Funktion getan zu halten, wenn möglich (aber auf der Suche fortgeschrittenere Ansätze zu lernen):Angeben optionaler Parameter außerhalb der Reihenfolge

(defstruct action 
    name duration slot1 slot2 slot3) 

(defmacro define-action (name &rest rest) 
    `(install-action ',name ',rest)) 

(defun install-action (name &rest rest) 
    (let* ((slots (first rest)) 
     (duration (if (numberp (first slots)) 
         (prog1 (first slots) 
           (setf slots (cdr slots)))        
        0)) 
     (action (make-action :name name :duration duration 
        :slot1 (first slots) :slot2 (second slots) 
        :slot3 (third slots)))) 
    (print action))) 

(define-action move a b c) ;first example no duration 

(define-action move 1 a b c) ;second example with duration=1 

#S(ACTION :NAME MOVE :DURATION 0 :SLOT1 A :SLOT2 B :SLOT3 C) 
#S(ACTION :NAME MOVE :DURATION 1 :SLOT1 A :SLOT2 B :SLOT3 C) 

Zusätzliche Klarstellung: Die Slot-Werte oben sind wirklich verschiedene Spezifikationen, die als (manchmal tief verschachtelte) Lisp-Bäume dargestellt werden. Die Funktion install-action interpretiert die Spezifikationen und installiert ihren semantischen Inhalt in einer Datenbank.

+1

zitieren Wenn die restlichen Parameter benötigt werden, wäre es besser, sie nur als reguläre benannte Parameter zu verwenden.Auf diese Weise können Benutzer des Makros aus der Lambda-Liste sehen, was sie ihm geben sollen, anstatt raten zu müssen (/ die Dokumente lesen). Die optionale Dauer könnte ein Schlüsselwort/optionaler Parameter am Ende sein. Oder Sie könnten etwas wie '(Name (und optional (Dauer 0)) slot1 slot2 slot3) für das Makro haben. – jkiiski

+0

Ich würde es vorziehen, Ihre Lösung zu verwenden, wenn ich es zur Arbeit bringen kann. (Wusste nicht, benötigt/optional könnte so gemischt werden.) Wie erhalten Sie (defacroc define-action (Name (und optional (Dauer 0)) slot1 slot2 slot3) '(Installation-Aktion ', Name', Dauer ', slot1', slot2 ', slot3)) Makroexpand richtig? (ps: Wie zeichnet man eine bevorzugte Lösung in Stackoverflow für einen Kommentar auf?) – davypough

+0

Das sollte funktionieren: '(macroexpand '(define-action foo (3) abc)) =>' (INSTALL-ACTION' FOO '3' A "B" C) ". Denken Sie daran, dass Sie um die Dauer herum Parens setzen müssen (oder leere Parens, wenn Sie keine Dauer haben). – jkiiski

Antwort

3

Parameter und Argumentlisten: style

Es ist sinnvoll explizite Parameterlisten zu haben. Common Lisp bietet umfangreiche Unterstützung dafür. Aber auch dann kann nicht jede Parameterlistenidee unterstützt werden. Wie jkiiski in seinem Kommentar bemerkt, ist es immer hilfreich, eine sprechende Parameterliste zu haben: Es hilft dem Entwickler, der Compiler kann einige Fehler zur Kompilierzeit auffangen, und Lisp kann bessere Debugging-Informationen liefern.

Eine der Stilregeln: optionale Argumente sollten am Ende der Argumentliste stehen. Common Lisp selbst verletzt diesen mindestens einen Ort (kann sich nur an eine Funktion erinnern) und ist immer schmerzhaft und fehleranfällig.

fixieren arglist von INSTALL-ACTION:

(defun install-action (name slots &optional (duration 0)) 
    ...) 

die arglist des Makros Fix auch

verwenden Sie es wie:

(define-action move (a b c) 1) 

Eine Liste der Dinge könnte besser in der Makroschnittstelle gruppiert werden.

(defmacro define-action (name slots &optional duration) 
    ...) 

Oder sogar ein Schlüsselwort benannten Argumente:

(define-action move :slots (a b c) :duration 1) 

Es wird immer länger, aber die Lesbarkeit stark verbessert.

Seitliche Frage: Brauchen wir ein Makro DEFINE-ACTION und warum?

Die wichtigsten Gründe für ein solches Makro sind in der Regel:

  • weniger
  • spezielle Syntax
  • Kompilierung-Nebenwirkungen
  • Expansion in andere Makroaufrufe
+1

Ein Wort fehlt: "optionale Argumente sollten an der der Argumentliste sein". – coredump

+1

@coredump: vielen Dank, behoben. –

+0

Ich hatte gehofft, den optionalen Parameter zweiter in der Lambda-Liste für das Lesen zu setzen. Es ist nur eine Zahl, und die Slot-Argumente sind möglicherweise komplexe Bäume (siehe Problembearbeitung oben). Besorgt, dass das optionale Argument am Ende beim Schreiben von Spezifikationen zu leicht übersehen werden könnte. Sind slot: keywords der beste Weg, obwohl sie alle benötigt werden? – davypough

Verwandte Themen