无法使用make-symbol

时间:2015-07-31 12:57:45

标签: emacs macros lisp elisp

我尝试编写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-1foo-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中呢?

1 个答案:

答案 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"

备注

  1. 如果您使用的是CL,那么未打印的符号将打印为#:foo-1,您的问题来源对您来说很明显。
  2. 确实需要使用make-symbol 非常罕见。通常,您要使用interngensym