【问题标题】:Why not allow quoted arguments in macros为什么不允许在宏中引用参数
【发布时间】:2019-12-15 16:51:04
【问题描述】:

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

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

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

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

通常你想向 HOOK 添加几个项目或者你希望 HOOK-FN 到几个 hooks,但是 add-hook 一次只接受一个 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 中的约定。为什么?是否有充分的理由不应该在宏中允许引用参数?

【问题讨论】:

  • 我认为一个词的答案是“品味”。

标签: macros lisp elisp quote


【解决方案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)))

等等:

(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)

【讨论】:

    猜你喜欢
    • 2015-02-19
    • 1970-01-01
    • 2023-03-27
    • 1970-01-01
    • 1970-01-01
    • 2017-12-10
    • 2012-02-14
    • 2010-12-10
    • 2018-04-30
    相关资源
    最近更新 更多