【问题标题】:In Common Lisp, how to define a macro expanding to nothing (rather than `nil`)?在 Common Lisp 中,如何定义一个扩展为空的宏(而不是 `nil`)?
【发布时间】:2013-09-10 14:32:25
【问题描述】:

我想定义一个可以注释s-expression的宏,例如:

希望

(list 1 2 (comment-macro (something))) -> (1 2)

但是如果我这样定义宏

(defmacro comment-macro (x))

上面表格的结果其实是

(1 2 nil)

【问题讨论】:

标签: macros common-lisp


【解决方案1】:

您无法使用 常规 宏完成您想要的,因为它的主值(或 nil,如果没有返回值)将始终被使用。

但是,有两种常见的选择:

  1. 评论:#| ... |# - 用于一般文本

  2. 特征表达式:#+(or) ... 或 #-(and) ... - 用于(暂时?)禁用代码

您还可以使用set-macro-character 和set-dispatch-macro-character 定义自己的read macros。

【讨论】:

  • #|...|# 实际上也是阅读器宏,它们也是更好的选择,因为条件阅读器宏旨在与功能一起使用。
  • 我真的很想要一个读宏。我认为如果我可以快速打开/关闭 s 表达式会很方便。但我只是不知道如何将它们扩展为空。
  • 读取宏还是普通宏? read 宏由阅读器扩展,常规宏由编译器/解释器扩展
  • 但是如何定义自己的读取宏呢?我知道如何定义调度宏,但它不起作用(总是返回nil)
  • @SaltyEgg 你可以看看On Lisp Chapter 17. Read Macros。此外,请参阅 HyperSpec 中的2.1.4.4 Macro Characters,它说“该函数要么返回已解析的对象,要么不返回任何值以指示函数扫描的字符被忽略(例如,在注释的情况下)。 "如果您想表示评论,请使用 (values) 返回零值。
【解决方案2】:

在 Common Lisp 中,无法定义扩展为空的宏。从宏返回的primary value(即macro function)总是插入到宏调用的位置。

【讨论】:

  • 这在技术上是正确的,但是@SaltyEgg 在其他 cmets 中澄清了需要读取宏,并且这些可以像 cmets(例如,#| ... |# 宏)。
  • 对;我的回答适用于最初陈述的问题。
  • 同意。我只是为遇到后者的任何读者强调了不同之处,尤其是在问题被编辑以更好地满足 OP 的愿望的情况下。
【解决方案3】:

简短的回答是你不能,但仍有许多其他方法可以解决它。

首先我考虑在宏的最后一句中使用 (values),但在 SBCL 中不起作用——它似乎等于 (values) 与 nil。

更简单的思考方式是使用remove:

(remove nil '(1 2 (comment-macro (x)))))

但它可能无法随时工作。

最好的方法是使用条件:

(aif (comment-macro (x)) (list 1 2 it) (list 1 2))

对于我遇到的条件,我只是把“我必须让它什么都不返回”的情况变成“在适当的条件下我构造适当的代码”。我希望它有效。

【讨论】:

    猜你喜欢
    • 2013-12-09
    • 1970-01-01
    • 2011-03-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-28
    • 2023-03-12
    • 2015-07-03
    相关资源
    最近更新 更多