无法使用我的Emacs-Lisp宏定义函数

时间:2017-09-26 14:04:22

标签: emacs macros elisp

我想弄清楚如何使用宏。我知道有其他方法可以解决这个问题,宏可能是也可能不是最好的答案,但我想了解这里的技术问题而不是其他方式解决它。

(setq model-names (list "goat" "alpaca" "llama"))

(defun some-fn (model tag)
  (message "Great news: %s %s" model tag))

(defmacro make-my-defun(model)
  `(defun ,(intern (concat "my-defun-" (eval model))) (tag)
     "Do a thing"
     (interactive "sTag: ")
     (some-fn ,(eval model) tag)))

(macroexpand-1 '(make-my-defun "goat"))
(macroexpand-1 '(make-my-defun (car model-names)))


(cl-loop for name in model-names
         do
;;         (insert (format "%s" name)))
         (make-my-defun name))

这几乎可行。我认为传递给宏的东西只是性别,而不是评估代码。但是,当我尝试在循环中创建这些函数时,它根本不起作用。使用上面的代码...

(make-my-defun "goat")
(make-my-defun (car model-names))

这两项都有效。没有eval它显然不会起作用,因为它会在第二个声明中获得原车expr。

那是怎么回事?为什么name在我的cl-loop中与make-my-defun有关?我阅读了关于宏和其他几个资源的文档,但是,我在这里缺乏一些基本的见解。

1 个答案:

答案 0 :(得分:1)

cl-loop是复杂的,但基本上,循环内的name绑定是通过cl-symbol-macrolet完成的,它扩展为解析绑定的代码。 eval在调用时无法知道这一点:因为(1)您不希望macroexpand下降到引用代码中; (2)你不希望eval以某种方式继承周围的词汇环境。当你写(car model-names)时,它是全局绑定的。

您已经使用了eval一次,我想您可以再次使用它:

(cl-loop for name in model-names
         do (eval `(make-my-defun ,name)))

但实际上,宏操作代码,他们通常不会评估。