I'm a Lisp beginner and I'm struggling to understand why the following code gives me an error.
(dolist (elem '(mapcar
mapcon))
(when (fboundp `',elem) (print "hello")))
Thanks.
Edit: A bit more context. I wrote the following in Elisp and I don't know how to fix it.
(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)))
In your question you mix common-lisp
and elisp
, but they are two different languages. The question however touches on concepts that are identical in both languages.
The code you want to write checks if a symbol is bound to a function.
What you already know probably is that you can call fboundp
on a symbol to determines this:
(fboundp 'menu-bar-mode)
=> t
When you evalute the above form, 'menu-bar-mode
is the same as (quote menu-bar-mode)
, and is evaluated as the symbol object menu-bar-mode
. This is the value that is given as an argument to fboundp
.
In you example you want to iterate over a list of symbols, call fboundp
on it and call the function if the symbol denotes a function. You can do this as follows:
(dolist (s '(menu-bar-mode and other symbols))
(when (fboundp s)
(funcall s -1)))
The list of symbols '(menu-bar-mode and other symbols)
is quoted, which means that when dolist
evaluates it, it sees a list of symbols. The value to which s
is bound at each iteration of the loop is a symbol object, there is no need to quote them.
Quoting a symbol is something you have to do when writing them in your code so that they are not interpreted as variables. When you iterate over a list of symbols, you already manipulate symbols.
Note also that both Common Lisp and Emacs Lisp are "Lisp-2", meanings that you have to use (funcall ui-elem -1)
instead of writing (ui-elem -1)
. When you write the latter form, that means calling the function literally named ui-elem
because for function application, the first symbol in the list is not evaluated, it is taken literally.
The actual error I have when I execute your code is:
(wrong-type-argument symbolp 'mapcar)
It may look like 'mapcar
denotes a symbol, because when you want the interpreter to evaluate some code as a symbol, you need to quote it. However, Lisp printers write objects in a way that they can be read back to "similar" objects. The error message that is printed if I expect a symbol to be a number is the following, where symbol foo
is printed unquoted:
(+ 'foo 3)
;; error: (wrong-type-argument number-or-marker-p foo)
In your error message, the form that you are trying to use as a symbol is (quote mapcar)
. Recall that when you directly call fboundp
:
(fboundp 'mapcar)
It is the same as-if you wrote:
(fboundp (quote mapcar))
First, (quote mapcar)
is evaluated, as the symbol mapcar
. Then, fboundp
is applied to that value.
But when you write the following, while ui-elem
is bound to symbol mapcar
:
(fboundp `',ui-elem)
This is equivalent to:
(fboundp `(quote ,ui-elem))
The argument to fboundp
is evaluated as (quote mapcar)
. You have one extra level of quoting. You could write instead:
(fboundp `,ui-elem)
But then, you don't need to use backquote/comma, you can directly write:
(fboundp ui-elem)