3

为什么对以下内容进行字节编译会产生警告?

(defmacro foomacro (shiftcode)
  `(defun foo (&optional arg)
     (interactive ,(concat shiftcode "p"))
     (message "arg is %i" arg))
  `(defun bar (&optional arg)
     (interactive ,(concat shiftcode "Nenter a number: "))
     (message "arg is %i" arg)))
;; provide backward compatibility for Emacs 22
(if (fboundp 'handle-shift-selection)
    (foomacro "^")
  (foomacro ""))

这是我得到的警告:

$ emacs -Q --batch --eval '(byte-compile-file "foo.el")'

In foomacro:
foo.el:1:21:Warning: value returned from (concat shiftcode "p") is unused

如果我摆脱bar,警告就会消失:

(defmacro foomacro (shiftcode)
  `(defun foo (&optional arg)
     (interactive ,(concat shiftcode "p"))
     (message "arg is %i" arg)))
;; provide backward compatibility for Emacs 22
(if (fboundp 'handle-shift-selection)
    (foomacro "^")
  (foomacro ""))

我正在使用 GNU Emacs 24.2.1。

4

1 回答 1

6

那是因为您忘记将宏主体包装在 progn 中:

(defmacro foomacro (shiftcode)
  `(progn
     (defun foo (&optional arg)
       (interactive ,(concat shiftcode "p"))
       (message "arg is %i" arg))
     (defun bar (&optional arg)
       (interactive ,(concat shiftcode "Nenter a number: "))
       (message "arg is %i" arg))))

想想宏是如何工作的。当您调用(foomacro "...")时,lisp 引擎会识别出这foomacro是一个宏并将其展开,即在提供的参数上调用它。宏的返回值,正如所料,是第二种 defun形式;而第一种 defun形式被丢弃。然后 lisp 引擎评估返回值(这是第二种 defun形式)。因此,在您的progn-less 版本中仅bar定义,而不是foo.

要理解这个过程,你需要意识到宏仅仅是“代码转换”工具;他们真的什么都不做。因此,编译器(或解释器)只能看到它们的返回值。

于 2013-06-13T02:31:47.703 回答