I've asked this question recentely on reddit but I thought perhaps I'd get a better answer here.
Often macros I write take either a symbol or a list of symbols and sometimes these symbols represent a variable or a function. And in these cases I'm tempted write the macros so that their arguments can be quoted or sharquoted. Here's a concrete example:
In emacs lisp the function add-hook adds HOOK-FN to a list named HOOK.
(add-hook 'hook #'hook-fn)
Often you want to add several items to HOOK or you want HOOK-FN to several hooks, but add-hook only takes in one hook or one hook-fn at a time. So, I made a macro for this called add-hook! which can accept multiple arguments.
(add-hook! hook-name (fn1 fn2 fn3))
;; or
(add-hook! (hook-name1 hook-name2) hook-fn)
I am inclined to allow arugments to the macro to be quoted or sharpquoted. Just as they would be in a function call.
(add-hook! 'hook-name #'fn)
To do this I'd use a function like this to strip off the quotes from each argument.
(defun unquote (form)
"Unquote a form if it is quoted, otherwise return form."
(if (member (car-safe it) '(quote function))
(cadr form)
form))
I am inclided to do this because quoting and sharpquoting (1) makes it clear whether I mean a function or a symbol and (2) triggers my autocompletion, which helps me type the function or symbol faster.
However, I am under the impression that this is not the convention in lisp. Why? Are there good reasons why you should not allow quoted arguments in macros?
You certainly can do that, but it looks a little strange, because it mixes visual signals that say “Function here, normal evaluation” and “Macro here, special evaluation”.
Why don't you make add-hook-fns
a (quite simple) function, just like add-hook
is? Then all the quoting naturally falls into place and is even required.
(defun add-hook-fns (hook fns)
(dolist (fn fns)
(add-hook hook fn)))
This would then look on invocation like this:
(add-hook-fns 'some-hook (list #'foo #'bar #'baz))
If you don't want that explicit call to list
in there, you can use a macro to eliminate just that:
(defmacro add-hook-fns* (hook fns)
`(add-hook-fns ,hook (list ,@fns)))
Et voilà:
(add-hook-fns* 'some-hook (#'foo #'bar #'baz))
However, I don't recommend that, see reasons at the start.
Instead, I'd still use just a function, but with rest parameters:
(defun add-hook-fns (hook &rest fns)
(dolist (fn fns)
(add-hook hook fn)))
Now:
(add-hook-fns 'some-hook #'foo #'bar #'baz)