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)
在您的问题中,您混合使用common-lisp
和elisp
,但它们是两种不同的语言。然而,这个问题涉及两种语言中相同的概念。
您要编写的代码检查符号是否绑定到函数。您可能已经知道的是,您可以调用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
的函数,因为对于函数应用程序,不会计算列表中的第一个符号,而是按字面意思执行。
我在执行您的代码时遇到的实际错误是:
Run Code Online (Sandbox Code Playgroud)(wrong-type-argument symbolp 'mapcar)
它可能看起来像'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)