本文介绍了无法使用make-symbol生成的名称调用宏中定义的函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试编写一个ELisp宏,以基于一些常见数据生成多个函数.例如,当我想计算fn名称时,我会写类似(我暂时不注意卫生,而是将符号文字传递到宏中,因此求值无关紧要):

I'm trying to write an ELisp macro to generate a multiple functions based on some common data. For example, when I want to compute the fn names I write something like (I'm ignoring hygiene for the moment, I'm passing a symbol literal into the macro so evaluation shouldn't matter):

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

I should then be able to invoke the macro and fns like so:

(def-fns foo)
(foo-1)
;; => 6
(foo-2)
;; -> "six

即使Emacs中(def-fns foo)的宏扩展也表明情况应该如此:

Even the macroexpansion of (def-fns foo) in Emacs suggests that this should be the case:

(progn
  (defun foo-1 nil (+ 1 2 3))
  (defun foo-2 nil "six"))

但是,当我评估def-fns定义并调用它时, not 不会生成那些函数.为什么会这样呢?该技术在Common Lisp和Clojure(它们具有非常相似的宏系统)中都有效,那么为什么不在ELisp中使用呢?

However, when I evaluate the def-fns definition and invoke it it does not generate those functions. Why is this the case? This technique works in Common Lisp and in Clojure (which have very similar macro systems), so why not in ELisp?

推荐答案

您的代码也无法在CL中工作.

Your code would not work in CL either.

问题出在 make-symbol -它会创建一个 new 符号,这样

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

这意味着您的宏会创建函数,但会将它们绑定到不再具有句柄的符号上.

This means that your macro creates the functions but binds them to symbols which you no longer have a handle on.

当您评估(foo-1)时,Emacs Lisp阅读器会尝试查找 interned 符号foo-1的功能绑定,而不是您的宏所创建的新鲜的uninterned符号.

When you evaluate (foo-1), Emacs Lisp reader tries to find the function binding of the interned symbol foo-1, not the fresh uninterned symbol your macro created.

您需要改用intern:可以说,该符号使通常可用":

You need to use intern instead: it makes the symbol "generally available", so to speak:

(eq (intern "a") (intern "a))
==> t

因此,更正后的代码如下:

So, the corrected code looks like this:

(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.
  1. If you were using CL, the uninterned symbols would have been printed as #:foo-1 and the source of your problem would have been obvious to you.
  2. It is exceedingly rare that you really need to use make-symbol. Usually, you want to use either intern or gensym.

这篇关于无法使用make-symbol生成的名称调用宏中定义的函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-29 23:37