根据我的经验,当人们看到宏如何帮助生成代码时,宏会给他们留下最好的印象,而这些代码是过程或其他构造无法实现的。很多时候这样的事情可能被描述为:
<common code>
<specific code>
<other common code>
其中<common code> 始终相同。以下是此类架构的一些示例:
1. time 宏。 没有宏的语言代码看起来像这样:
int startTime = getCurrentTime();
<actual code>
int endTime = getCurrentTime();
int runningTime = endTime - startTime;
您不能将所有通用代码都放入过程中,因为它包含实际代码。 (好吧,如果语言支持,你可以在 lambda 函数中创建一个过程并传递实际代码,但并不总是很方便)。
而且,您很可能知道,在 Lisp 中,您只需创建 time 宏并将实际代码传递给它:
(time
<actual code>)
2。事务。 要求 Java 程序员用 JDBC 编写简单的 SELECT 方法 - 这需要 14-17 行,包括打开连接和事务的代码,关闭它们,几个嵌套的 try-catch-finally 语句,只有 1或 2 行唯一代码。
在 Lisp 中,您只需编写 with-connection 宏并将代码减少到 2-3 行。
3.同步。好的,Java、C# 和大多数现代语言已经有了它的声明,但是如果你的语言没有这样的结构怎么办?或者,如果您想引入新的同步类型,例如基于STM 的事务?同样,您应该为此任务编写单独的类并手动使用它,即在要同步的每个语句周围放置通用代码。
这只是几个例子。您可以提及像with-open 系列这样的“不可忘记”宏,它可以清理环境并保护您免受资源泄漏,像cond 这样的新构造宏而不是多个ifs,当然,不要不要忘记像 if、or 和 and 这样的惰性结构,它们不会评估它们的参数(与过程应用程序相反)。
一些程序员可能会主张,他们的语言有一种技术来处理这种或那种情况(ORM、AOP 等),但问他们,如果存在宏,是否需要所有这些技术?
因此,将其全部纳入并回答有关如何解释宏的原始问题。将 Java 中任何广泛使用的代码(C#、C++ 等)转换为 Lisp,然后将其重写为宏。