[英]How to prevent macroexpand-all to skip first form in list?
我正在嘗試擴展嵌套列表結構中的所有宏。 macroexpand-all 幾乎可以工作,但跳過(不展開)每個嵌套列表中的第一種形式。
我將其用作 org-agenda-custom-commands 的模板機制。 我可以通過宏為多個議程命令生成議程塊。 這是在 init.el (emacs26.2) 中。 macroexp-all-forms 不能跳過第一個表單,而是為嵌套表單調用 macroexpand-all。
這是 emacs 文檔中的一個最小示例:
(defmacro inc (var)
(list 'setq var (list '1+ var)))
這按預期工作(一個宏調用):
ELISP> (macroexpand-all '(inc r))
(setq r
(1+ r))
這也有效(嵌套,但第一種形式不是宏調用):
ELISP> (macroexpand-all '(('foo)(inc r)))
(('foo)
(setq r
(1+ r)))
這難道不是不工作(嵌套和第一種形式是宏調用):
ELISP> (macroexpand-all '((inc r)(inc r)))
((inc r)
(setq r
(1+ r)))
這也不起作用:
ELISP> (macroexpand-all '((inc r)))
((inc r))
在最后兩個示例中,對 inc的第一次調用未擴展。 我在這里缺少什么? 在這種情況下,我如何才能真正擴展所有宏?
macroexpand-all
需要一個形式作為參數,但((inc r) (inc r))
不是一個形式。 表單應該是可以評估的東西。 在列表的情況下,這意味着第一個元素必須是函數、宏或特殊運算符或 lambda 表達式的名稱。
特殊運算符progn
可用於progn
順序評估的表單列表。 例如:
(macroexpand-all '(progn (inc r) (inc r)))
;=> (progn
; (setq r
; (1+ r))
; (setq r
; (1+ r)))
或者,如果列表不是表單,您可以使用mapcar
將macroexpand-all
應用於列表的每個成員。 例如:
(mapcar #'macroexpand-all '((inc r) (inc r)))
;=> ((setq r
; (1+ r))
; (setq r
; (1+ r)))
請記住,這里的結果是表單列表,而不是表單本身; 它不能按原樣進行評估,但可以對各個元素進行評估。
您想要擴展的表單作為評估表單應該是有意義的。 ((inc r))
不是:它不能是合法的 elisp。
我實際上很驚訝macroexpand-all
在你給出的情況下不會引發錯誤。 如果你想讓它工作,你需要偽造一些可能合法的東西。 例如
ELISP> (macroexpand-all '(grut (inc r) (inc r)))
(grut
(setq r
(1+ r))
(setq r
(1+ r)))
ELISP> (cdr (macroexpand-all '(grut (inc r) (inc r))))
((setq r
(1+ r))
(setq r
(1+ r)))
grut
不需要定義:它只需要不是一個宏,以便macroexpand-all
忽略它。 (實際上,按照jkiiski 的建議使用progn
是更好的答案)。
順便說一句,聽起來您正在使用宏擴展來做一些不同於擴展 Lisp 代碼的事情:這幾乎總是一個壞主意。 最好編寫自己的擴展器,它了解您在 Lisp 中實現的語言的規則。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.