gpt4 book ai didi

emacs - 无法使用 make-symbol 生成的名称调用宏中定义的函数

转载 作者:太空宇宙 更新时间:2023-11-03 18:36:26 24 4
gpt4 key购买 nike

我正在尝试编写一个 ELisp 宏来根据一些公共(public)数据生成多个函数。例如,当我想计算 fn 名称时,我写了类似的东西(我暂时忽略卫生,我将符号文字传递到宏中,因此评估无关紧要):

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

最佳答案

您的代码也无法在 CL 中运行。

问题出在make-symbol - 它创建了一个新的符号,这样

(eq (make-symbol "A") (make-symbol "A"))
==> nil

这意味着您的宏创建了函数,但将它们绑定(bind)到您不再能处理的符号。

当您评估(foo-1)时,Emacs Lisp 阅读器会尝试找到interned 符号foo-1 的函数绑定(bind),不是您的宏创建的新的 uninterned 符号。

您需要改用 intern:它使符号“普遍可用”,可以这么说:

(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

关于emacs - 无法使用 make-symbol 生成的名称调用宏中定义的函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31746791/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com