簡體   English   中英

如何防止 macroexpand-all 跳過列表中的第一個表單?

[英]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)))

或者,如果列表不是表單,您可以使用mapcarmacroexpand-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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM