2017-09-26 96 views
2

我想弄清楚如何使用宏。我知道还有其他方法可以解决这个问题,而宏观可能是最好的答案,但我想了解这里的技术问题,或者以其他方式解决问题。无法用我的Emacs-Lisp宏定义函数

(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)) 

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

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

这两个工作。如果没有评估,它显然不会起作用,因为它会在第二个声明中获得原车expr。

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

回答

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))) 

但实际上,在宏代码运行时,他们通常不评价。

+0

这是有道理的。使用宏来模板函数似乎不适合宏观设施。 虽然我最终使用'eval'来处理'(macroexpand-1 ..)'的结果,但我的工作基本上按照您的建议来完成。感谢您的想法和解释。 –