我尝试编写ELisp
宏来根据一些常见数据生成多个函数。例如,当我想要计算fn名称时,我写了类似的东西(我暂时忽略了卫生,我将符号文字传递给宏,因此评估不应该重要):< / p>
(cl-defmacro def-fns (sym)
"SYM."
(let ((s1 (make-symbol (concat (symbol-name sym) "-1")))
(s2 (make-symbol (concat (symbol-name sym) "-2"))))
`(progn (defun ,s1 () (+ 1 2 3))
(defun ,s2 () "six"))))
我希望在调用时生成2个fns,称为foo-1
和foo-2
。
然后我应该能够像这样调用宏和fns:
(def-fns foo)
(foo-1)
;; => 6
(foo-2)
;; -> "six
即使Emacs中(def-fns foo)
的宏观扩展也表明情况应该如此:
(progn
(defun foo-1 nil (+ 1 2 3))
(defun foo-2 nil "six"))
但是,当我评估def-fns
定义并调用它时,不生成这些函数。为什么会这样?这种技术适用于Common Lisp和Clojure(它们具有非常相似的宏系统),那么为什么不在ELisp中呢?
答案 0 :(得分:9)
您的代码也无法在CL中使用。
问题在于make-symbol
- 它会创建一个新的符号,以便
(eq (make-symbol "A") (make-symbol "A"))
==> nil
这意味着您的宏会创建函数,但会将它们绑定到您不再拥有句柄的符号上。
当您评估(foo-1)
时,Emacs Lisp阅读器会尝试查找实习符号foo-1
的功能绑定,而不是宏创建的新未处理符号。
您需要使用intern
:它使符号&#34;通常可用&#34;,可以这么说:
(eq (intern "a") (intern "a))
==> t
因此,更正后的代码如下所示:
(defmacro def-fns (sym)
"SYM."
(let ((s1 (intern (concat (symbol-name sym) "-1")))
(s2 (intern (concat (symbol-name sym) "-2"))))
`(progn (defun ,s1 () (+ 1 2 3))
(defun ,s2 () "six"))))
(def-fns foo)
(foo-1)
==> 6
(foo-2)
==> "six"
备注强>:
#:foo-1
,您的问题来源对您来说很明显。make-symbol
非常罕见。通常,您要使用intern
或gensym
。