Ich habe immer Verwirrung über macro
in Emacs. Es gibt viele Dokumente über die Verwendung von macro
. Aber die Dokumente erwähnen nur die Oberfläche und Beispiele sind oft zu einfach. Außerdem ist es sehr schwierig, selbst nach macro
zu suchen. Es wird Tastaturmakroergebnisse ergeben.Compile Expansion Mysterium von Makro in Elisp
Die Leute sagen immer Makro wird zur Kompilierzeit erweitert und es ist so schnell wie das Schreiben der gleichen Kopie des Codes direkt. Ist das immer wahr?
Ich beginne mit dem Beispiel when
.
(pp-macroexpand-expression
'(when t
(print "t")))
;; (if t
;; (progn
;; (print "t")))
Wenn wir when
beim Kompilieren verwenden, wird die (if t .....)
direkt an unseren Code eingefügt, nicht wahr?
Dann finde ich ein komplizierteres Beispiel dotimes
von subr.el
. Ich vereinfacht den Code ein bisschen:
(defmacro dotimes (spec &rest body)
(declare (indent 1) (debug dolist))
(let ((temp '--dotimes-limit--)
(start 0)
(end (nth 1 spec)))
`(let ((,temp ,end)
(,(car spec) ,start))
(while (< ,(car spec) ,temp)
,@body
(setq ,(car spec) (1+ ,(car spec))))
,@(cdr (cdr spec)))))
Was meine Aufmerksamkeit der (end (nth 1 spec))
ist. Ich denke dieser Teil muss zur Laufzeit gemacht werden. Wenn dies zur Laufzeit ausgeführt wird, bedeutet dies, dass die Codeerweiterung nicht zur Kompilierzeit durchgeführt werden kann. Um es zu testen, habe ich die dotimes
ein bisschen modifiziert und die Datei kompiliert.
(defmacro my-dotimes (spec &rest body)
(declare (indent 1) (debug dolist))
(let ((temp '--dotimes-limit--)
(start 0)
;; This is my test
(end (and (print "test: ")(print (nth 1 spec)) (nth 1 spec))))
`(let ((,temp ,end)
(,(car spec) ,start))
(while (< ,(car spec) ,temp)
,@body
(setq ,(car spec) (1+ ,(car spec))))
,@(cdr (cdr spec)))))
(provide 'my)
Ergebnis
(require 'my)
(my-dotimes (var 3)
(print "dotimes"))
;; "test: "
;; 3
;; "dotimes"
;; "dotimes"
;; "dotimes"
der Tat ist mein Test-Anweisung zur Laufzeit erfolgen. Wenn es um die Expansion:
(pp-macroexpand-expression
'(my-dotimes (var 3)
(print "dotimes")))
;; (let
;; ((--dotimes-limit-- 3)
;; (var 0))
;; (while
;; (< var --dotimes-limit--)
;; (print "dotimes")
;; (setq var
;; (1+ var))))
Überraschenderweise mein Testteil verloren.
So ist dotimes
zur Laufzeit erweitert?
Wenn ja, bedeutet das, dass es den Vorteil eines generischen macro
verliert, dass macro
so schnell ist, wie der gleiche Code direkt schreiben?
Was macht der Interpreter, wenn er macro
erfüllt, die Laufzeitkomponenten haben und?
Endlich habe ich alles richtig gemacht. Ich habe lange verwirrt, weil ich nie eine Datei kompiliert habe, die das Makro verwendet. Ich habe nur die Makrodatei selbst byte-kompiliert. Und wenn jemand eine Datei byte-kompiliert, MUSS Makro erweitert werden. Das sind die zwei Punkte, mit denen ich vorher Probleme hatte. Sie können nicht wissen, wie viel ich Ihrer Antwort dankbar war. – tom