【问题标题】:How to prevent macroexpand-all to skip first form in list?如何防止宏扩展全部跳过列表中的第一个表单?
【发布时间】:2019-11-22 01:51:27
【问题描述】:

我正在尝试扩展嵌套列表结构中的所有宏。 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 没有展开。我在这里想念什么? 在这种情况下,我怎样才能真正扩展所有宏?

【问题讨论】:

    标签: emacs elisp-macro


    【解决方案1】:

    macroexpand-all 需要 form 作为参数,但 ((inc r) (inc r)) 不是一种形式。表单应该是可以评估的东西。对于列表,这意味着第一个元素必须是函数、宏或特殊运算符或 lambda 表达式的名称。

    特殊运算符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)))
    

    请记住,这里的结果是表单列表,而不是表单本身;它不能按原样评估,但可以对单个元素进行评估。

    【讨论】:

      【解决方案2】:

      您要扩展的表单作为评估表单应该是有意义的。 ((inc r)) 不:不能是合法的省略号。

      我真的很惊讶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 只是忽略它。 (实际上,使用progn 作为jkiiski suggests 是更好的答案)。

      顺便说一句,听起来您正在使用宏扩展来做一些除了扩展 Lisp 代码之外的事情:这几乎总是一个坏主意。最好编写自己的扩展器,它可以理解您在 Lisp 中实现的语言规则。

      【讨论】:

        猜你喜欢
        • 2015-01-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多