为什么不允许在宏中使用引号的参数

问题描述 投票:0回答:1

我最近在reddit上问过这个问题,但我想也许我会在这里得到更好的答案。

我编写的宏通常采用一个符号或符号列表,有时这些符号表示变量或函数。在这些情况下,我很想编写宏,以便可以对它们的参数进行引用或共享。这是一个具体的例子:

在emacs lisp中,功能add-hook将HOOK-FN添加到名为HOOK的列表中。

(add-hook 'hook #'hook-fn)

通常,您想将多个项目添加到HOOK或将HOOK-FN添加到多个钩子,但是add-hook一次只能容纳一个钩子或一个钩子-fn。因此,我为此创建了一个名为add-hook的宏!可以接受多个参数。

(add-hook! hook-name (fn1 fn2 fn3))

;; or

(add-hook! (hook-name1 hook-name2) hook-fn)

我倾向于允许对宏的修饰符加引号或加引号。就像它们在函数调用中一样。

(add-hook! 'hook-name #'fn)

为此,我将使用类似这样的函数来去除每个参数中的引号。

(defun unquote (form)
  "Unquote a form if it is quoted, otherwise return form."
  (if (member (car-safe it) '(quote function))
      (cadr form)
    form))

我之所以这样做是因为用引号和右引号(1)可以清楚地知道我是指一个函数还是一个符号,而(2)会触发我的自动补全,这有助于我更快地键入该函数或符号。

但是,我给人的印象是这不是轻率的惯例。为什么?是否有充分的理由说明为什么您不应该在宏中使用带引号的参数?

macros lisp quote
1个回答
1
投票

您当然可以这样做,但是它看起来有些奇怪,因为它混合了视觉信号,分别表示“功能正常,正常评估”和“宏功能,特殊评估”。

为什么不像add-hook-fns那样使add-hook一个(非常简单的)函数?然后所有报价自然都落入地方,甚至是必需的。

(defun add-hook-fns (hook fns)
  (dolist (fn fns)
    (add-hook hook fn)))

然后,它将像这样查看调用:

(add-hook-fns 'some-hook (list #'foo #'bar #'baz))

如果您不想在那里显式调用list,则可以使用宏消除该错误:

(defmacro add-hook-fns* (hook fns)
  `(add-hook-fns ,hook (list ,@fns)))

Etvoilà:

(add-hook-fns* 'some-hook (#'foo #'bar #'baz))

但是,我不建议这样做,请先查看原因。

相反,我仍然只使用一个函数,但是带有其余参数:

(defun add-hook-fns (hook &rest fns)
  (dolist (fn fns)
    (add-hook hook fn)))

现在:

(add-hook-fns 'some-hook #'foo #'bar #'baz)
© www.soinside.com 2019 - 2024. All rights reserved.