读取宏:你用它们做什么?

18

我正试图了解到目前为止我没有太多使用过的 Lisp 的部分。读取宏目前引起了我的注意。关于它们的用途并没有太多的信息,看看别人用它做了什么会有所帮助,既可以得到它们的工作方式的示例,也可以看到可以通过它们解决哪些问题。基于此,是否有任何指南来了解什么是读取宏的好和坏用法?

7个回答

20

S-表达式是 Lisp 中 Lisp 数据的语法。 S-表达式通过函数 READ 进行读取,读取宏是 Lisp 扩展阅读器的内置方式。这意味着读取宏最直接的用途是实现预定义的数据语法,并打开更改或扩展 Lisp 读取 s-表达式的方式的可能性。

Lisp 预定义了许多数据类型的外部语法:符号、数字、字符串、数组、字符、conses、列表、结构等等。它允许数据对象被打印和读回。

  1. Lisp 缺少一些其他数据类型的语法 - 特别是哈希表和 CLOS 对象。因此,用户代码中使用读取宏的第一个用途将是扩展阅读器以能够读取数据结构,如哈希表、并行向量、新数字类型等,基本上是开发人员想要具有可读回外部语法的每种数据类型。

  2. 由于 Lisp 也将 s-表达式用于代码,因此读取宏的第二个用途是扩展 Lisp 程序的符号表示法。典型示例是使用 [ 和 ] 编写嵌入式 SQL 代码。通常的 Lisp 语法看起来类似,但使用 [ 和] 可以使 SQL 表达式在代码中突出显示。另一个示例是使用读取宏为嵌入式编程语言提供标识符,例如 Objective C 常量、消息等。Clozure CL 使用此功能表示区分大小写 / 保留大小写标识符,并在读取时使用外部可用标识符的索引查找其定义。

  3. 第三种用途是将不同的语法嵌入到 Lisp 语法中。一个旧的例子是中缀读取宏,允许嵌入中缀表达式。其他例子包括嵌入式 HTML 或 XML 语法,或嵌入其他编程语言语法的片段。

  4. 有时,读取宏被用于实现使用与预定义 Common Lisp 语法略有不同的 s-表达式语法的其他(相关)语言。一个例子是 Scheme s-表达式的阅读器 - 这与 Common Lisp 稍有不同。


7

当需要使用字面对象的语法时,可以使用读取宏。唯一的问题是可能的语法扁平命名空间(但是,有方法可以解决这个问题)。

读取宏的用途并不是很多。我能想到的一些例子包括:


4

我通常会在普通的Lisp代码中避免使用它们;最近,我甚至因为第三方库使用了阅读器宏而拒绝使用它。这主要是因为与符号不同,阅读器宏只有一个“名称空间”。当选择适当的调度字符时,我经常与库的作者意见不合。

但是,我成功地使用自定义的非标准读取表和read完成简单的解析任务。到目前为止,我使用自定义的readtable实现的最复杂的解析器是一个HTML模板引擎(又一个,抱歉),其语法类似于JSP/ASP,但使用Common Lisp作为实际的模板语言,因此您可以使用以下内容:

<% (for (title . link) in breadcrumb do %><a href="<%= link %>"><%= title %></a><% ) %>

(仅供参考):这段代码不仅仅是通过readtable技巧完成的,还需要经过预处理阶段。

2
我在Github上有两个小项目,展示了为什么和如何使用Common Lisp中的读取宏。它们是SHELLSHOCKBOXEN。正如其他答案中提到的那样,CL-INTERPOL是一个杰出且有用的例子。
当然,这些是否是好的读取宏使用方式显然是主观的,但我肯定认为它们是有用的,否则我就不会写这些代码了!

2

虽然我使用了很多宏,但我从未发现需要使用读取宏,除了偶尔的实验。如果有帮助的话,在“Let Over Lambda”中您会找到关于它们的广泛讨论:http://letoverlambda.com/index.cl/toc


2

其中一种特别常见和有用的替代语法,你可以使用读取宏嵌入正则表达式语法。这种实现并不难,因为它只是使用不同的转义规则读取字符串,但如果你经常使用正则表达式,它确实会带来很多好处。dmitry-vk提到的CL-INTERPOL库提供了这个功能,以及许多其他功能。


0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接