Lisp 中的反引号扩展

aad*_*dcg 2 lisp elisp common-lisp quote

我是 Lisp 初学者,我正在努力理解为什么下面的代码给我一个错误。

(dolist (elem '(mapcar
                mapcon))
  (when (fboundp `',elem) (print "hello")))
Run Code Online (Sandbox Code Playgroud)

谢谢。

编辑: 更多的上下文。我在 Elisp 中写了以下内容,但我不知道如何修复它。

(dolist (ui-elem '(menu-bar-mode
                   tool-bar-mode
                   tooltip-mode
                   scroll-bar-mode
                   horizontal-scroll-bar-mode))
  (when (fboundp `',ui-elem) (ui-elem -1)))
Run Code Online (Sandbox Code Playgroud)

cor*_*ump 5

笔记

在您的问题中,您混合使用common-lispelisp,但它们是两种不同的语言。然而,这个问题涉及两种语言中相同的概念。

需要引用符号

您要编写的代码检查符号是否绑定到函数。您可能已经知道的是,您可以调用fboundp一个符号来确定这一点:

(fboundp 'menu-bar-mode)
=> t
Run Code Online (Sandbox Code Playgroud)

当您评估上述形式时,'menu-bar-mode与 相同(quote menu-bar-mode),并被评估为符号对象menu-bar-mode。这是作为参数提供给 的值fboundp

在您的示例中,您要遍历符号列表,调用fboundp它并在符号表示函数时调用该函数。您可以按如下方式执行此操作:

(dolist (s '(menu-bar-mode and other symbols))
  (when (fboundp s)
    (funcall s -1)))
Run Code Online (Sandbox Code Playgroud)

符号列表'(menu-bar-mode and other symbols)被引用,这意味着在dolist评估它时,它会看到一个符号列表。s在循环的每次迭代中绑定的值是一个符号对象,不需要引用它们。

引用符号是在代码中编写它们时必须做的事情,这样它们就不会被解释为变量。当您迭代符号列表时,您已经在操作符号。

还需要注意的是两者的Common Lisp和的Emacs Lisp是“Lisp的-2”的含义,你必须使用(funcall ui-elem -1)的,而不是写作(ui-elem -1)。当您编写后一种形式时,这意味着调用按字面命名ui-elem的函数,因为对于函数应用程序,不会计算列表中的第一个符号,而是按字面意思执行。

引用级别太多

我在执行您的代码时遇到的实际错误是:

(wrong-type-argument symbolp 'mapcar)
Run Code Online (Sandbox Code Playgroud)

它可能看起来像'mapcar表示一个符号,因为当希望解释器将某些代码评估为一个符号时,您需要引用它。然而,Lisp 打印机以一种可以将它们回“相似”对象的方式写入对象。如果我希望符号是数字,则打印的错误消息如下,其中符号foo打印时不加引号:

(+ 'foo 3)

;; error: (wrong-type-argument number-or-marker-p foo)
Run Code Online (Sandbox Code Playgroud)

在您的错误消息中,您尝试用作符号的形式是 (quote mapcar)。回想一下,当您直接调用时fboundp

(fboundp 'mapcar)
Run Code Online (Sandbox Code Playgroud)

就像你写的一样:

(fboundp (quote mapcar))
Run Code Online (Sandbox Code Playgroud)

首先,(quote mapcar)被评估为符号mapcar。然后,fboundp应用于该值。

但是,当您编写以下内容时, whileui-elem绑定到符号mapcar

(fboundp `',ui-elem)
Run Code Online (Sandbox Code Playgroud)

这相当于:

(fboundp `(quote ,ui-elem))
Run Code Online (Sandbox Code Playgroud)

的参数fboundp评估(quote mapcar)。你有一个额外的引用级别。你可以写:

(fboundp `,ui-elem)
Run Code Online (Sandbox Code Playgroud)

但是,你不需要使用反引号/逗号,你可以直接写:

(fboundp ui-elem)
Run Code Online (Sandbox Code Playgroud)