我可以在emacs lisp宏中添加条件吗?

时间:2016-01-24 06:51:10

标签: macros elisp

如何实现这样的目标?

(defmacro mood (x)
  (if (equal (symbol-name x) "t")
      `(defun happy ()
         (message "Happy"))
    `(defun sad ()
       (message "Sad")))
  )

我的目标是根据参数创建不同的功能。 这样做有什么问题吗?

2 个答案:

答案 0 :(得分:2)

编辑2:您是对的 - 对于在扩展时评估的代码完全依赖对(未评估的)宏的值的情况参数,我认为根据这些参数有条件地生成宏的返回表单是安全的。

您只需要注意,任何以动态值为条件的行为都需要作为扩展表单的一部分来处理。

(例如,如果宏参数是变量,并且您在条件中测试变量值,那么在扩展时进行该测试将是不安全的,因为该值是可能会在宏的扩展时间和评估扩展代码的时间之间发生变化。)

因此,您问题中的具体示例确实是安全的,因此在这种情况下,我的变体(下面)实际上并不是必需的。然而,扩展时评估肯定是你一般要谨慎的事情。

初步答案如下......

宏在编译时扩展。 (或者在最新版本的Emacs中,如果没有可用的字节编译版本的库,它们通常会在加载时“”“热切地”编译。)

在这些情况下,任何不属于宏返回形式一部分的代码,每个会话最多只能评估一次,但很可能只有一次对于给定的代码扩展(然后可以多次调用扩展代码)。

如果您需要扩展代码在运行时有条件地执行,则条件必须是宏返回的表单的一部分。

编辑:例如,我想你实际上想要写更多类似的内容:

(defmacro mood (x)
  `(if (equal (symbol-name ,x) "t")
       (defun happy ()
         (message "Happy"))
     (defun sad ()
       (message "Sad"))))

虽然你(几乎)不想通过比较它们的symbol-name来比较符号。您已经假设宏参数将计算为符号,因此只需将符号直接与eq进行比较:

(defmacro mood (x)
  `(if (eq ,x t)
       (defun happy ()
         (message "Happy"))
     (defun sad ()
       (message "Sad"))))

然后,例如,(mood 'foo)扩展为(由 M-x pp-macroexpand-last-sexp提供):

(if
    (eq 'foo t)
    (defun happy nil
      (message "Happy"))
  (defun sad nil
    (message "Sad")))

答案 1 :(得分:0)

定义它没有问题。实际上,你的代码几乎可以工作:

(defmacro mood (x)
  (if (equal x t)
      `(defun happy ()
         (message "Happy"))
    `(defun sad ()
       (message "Sad"))))

由于if不在后引号中,我们可以直接检查x的值。使用不同的参数扩展此定义表明定义了不同的函数:

> (macroexpand '(mood t))
(defalias (quote happy) (function (lambda nil (message "Happy"))))

> (macroexpand '(mood nil))
(defalias (quote sad) (function (lambda nil (message "Sad"))))