Der Ansatz format
mit funktioniert nicht, wenn ein Teil der I/O-verbundene Variablen geändert werden. Die Verwendung von format
zum Generieren von Symbolnamen ist im Allgemeinen ziemlich spröde und nicht portabel. Diese ist ein hartes Problem zu lösen, und es könnte einfacher sein, es mit List-Konstruktion eher als Backquotes allein zu nähern. Zum Beispiel könnte in diesem Fall haben wir:
(defmacro definline (name variables &body body)
(list 'define-compiler-macro name variables
`(list* 'let (list ,@(mapcar (lambda (variable)
`(list (quote ,variable) ,variable))
variables))
',body)))
Dies funktioniert so, dass:
CL-USER> (pprint (macroexpand-1 '(definline foobar (a b)
(print "foobar")
(+ a b))))
(DEFINE-COMPILER-MACRO FOOBAR
(A B)
(LIST* 'LET (LIST (LIST 'A A) (LIST 'B B)) '((PRINT "foobar") (+ A B))))
was, es sei denn, ich bin etwas Verlesen, sollten die gleichen Ergebnisse wie:
(define-compiler-macro foobar (a b)
`(let ((a ,a) (b ,b))
(print "foobar")
(+ a b)))
Ich glaube nicht, dass es unbedingt möglich ist, die letztere Form nur mit Backquotes zu generieren. Das Problem ist, dass, da die Spezifikation nicht genau definieren, wie Backquote implementiert ist, wird es als so etwas wie
(define-compiler-macro foobar (a b)
(backquote (let ((a (unquote a))
(b (unquote b)))
(print "foobar")
(+ a b)))
nicht so einfach Wenn Ihre Implementierung nicht es so implementieren, dann könnte man eine Erweiterung schreiben das erzeugt diese Art von Ausgabe. Sofern Sie nicht eine solche Garantie von Ihrer Implementierung erhalten, glaube ich nicht, dass es eine Möglichkeit gibt, die "Komma-Variable", die Sie injizieren müssen, in die höhere Ebene zu bekommen. Es ist schwer, diesen Punkt klar zu machen, aber man könnte in diesem Versuch aussehen:
(defmacro definline (name variables &body body)
`(define-compiler-macro ,name ,variables
`(let ,',(mapcar (lambda (variable)
`(,variable (unquote ,variable)))
variables)
,@',body)))
, dass die Ergebnisse wie produzieren:
(DEFINE-COMPILER-MACRO FOOBAR
(A B)
'(LET ((A (UNQUOTE A)) (B (UNQUOTE B)))
(PRINT "foobar")
(+ A B)))
Beachten Sie, dass SBCL schon klug genug ist, um die Backquote mit einem normalen zu ersetzen zitieren, da es nichts gibt, was innen nicht zitiert werden müsste. Das mapcar
generiert das Formular, das in gespleißt wird, kann Code mit Kommas darin nicht generieren, da es nicht angegeben wird, wie diese Kommas implementiert werden, und laut 2.4.7 Comma "ist Komma ungültig, wenn es anders als in dem Körper eines backquote verwandt wird Ausdruck".Ich denke, das bedeutet, dass die beste Option ist so etwas wie:
(defmacro definline (name variables &body body)
`(define-compiler-macro ,name ,variables
`(let ,(mapcar 'list
',variables
(list ,@variables))
,@',body)))
Die Erweiterung dieser wird unter verschiedenen Implementierungen, anders sein, aber in SBCL es ist:
(DEFINE-COMPILER-MACRO FOOBAR (A B)
`(LET (SB-IMPL::BACKQ-COMMA (MAPCAR 'LIST '(A B) (LIST A B)))
(PRINT "foobar")
(+ A B)))
In CCL erhalten Sie:
(DEFINE-COMPILER-MACRO FOOBAR (A B)
(LIST* 'LET
(LIST* (MAPCAR 'LIST '(A B) (LIST A B))
'((PRINT "foobar") (+ A B)))))
In CLISP:
(DEFINE-COMPILER-MACRO FOOBAR (A B)
(CONS 'LET
(CONS (MAPCAR 'LIST '(A B) (LIST A B)) '((PRINT "foobar") (+ A B)))))
Aufrufen der generierten Compiler-Makrofunktion, z. "(funcall (compiler-macro-function 'foobar)' (foobar 10 11)())" kann ein nützliches Werkzeug sein, um die Ausgabe hier zusätzlich zu macroexpand-1 zu verifizieren. –
Danke für die ausgezeichnete Erklärung! – asm