为什么不允许在宏中引用参数
Why not allow quoted arguments in macros
我最近在 reddit 上问过这个问题,但我想也许我会在这里得到更好的答案。
我编写的宏通常采用符号或符号列表,有时这些符号代表变量或函数。在这些情况下,我很想编写宏,以便可以引用或引用它们的参数。这是一个具体的例子:
在 emacs lisp 中,add-hook 函数将 HOOK-FN 添加到名为 HOOK 的列表中。
(add-hook 'hook #'hook-fn)
经常你想添加几个项目到HOOK或者你想HOOK-FN到几个钩子,但是add-hook一次只接受一个钩子或一个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) 触发了我的自动完成功能,这有助于我更快地键入函数或符号。
但是,我的印象是这不是 lisp 中的惯例。为什么?有充分的理由说明您不应在宏中使用引号吗?
你当然可以这样做,但它看起来有点奇怪,因为它混合了“这里是函数,正常评估”和“这里是宏,特殊评估”的视觉信号。
为什么不让 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)))
瞧瞧:
(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)
我最近在 reddit 上问过这个问题,但我想也许我会在这里得到更好的答案。
我编写的宏通常采用符号或符号列表,有时这些符号代表变量或函数。在这些情况下,我很想编写宏,以便可以引用或引用它们的参数。这是一个具体的例子:
在 emacs lisp 中,add-hook 函数将 HOOK-FN 添加到名为 HOOK 的列表中。
(add-hook 'hook #'hook-fn)
经常你想添加几个项目到HOOK或者你想HOOK-FN到几个钩子,但是add-hook一次只接受一个钩子或一个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) 触发了我的自动完成功能,这有助于我更快地键入函数或符号。
但是,我的印象是这不是 lisp 中的惯例。为什么?有充分的理由说明您不应在宏中使用引号吗?
你当然可以这样做,但它看起来有点奇怪,因为它混合了“这里是函数,正常评估”和“这里是宏,特殊评估”的视觉信号。
为什么不让 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)))
瞧瞧:
(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)