C++ Lisp宏的特殊用法?

C++ Lisp宏的特殊用法?,c++,macros,lisp,C++,Macros,Lisp,我最近读了一本黑客和画家的书。作者说Lisp宏比其他语言的宏功能强大且特殊 我开始学习ELisp宏,但仍然不知道它有什么特殊用途?看不出它和C/C++宏之间的区别 有人能给我解释一下吗> LISP宏允许您在比C++宏更深层的地方修改语言。Lisp宏是在编译阶段执行的代码片段,它们可以控制参数的计算 例如,Lisp基于编译器必须处理的25个“特殊形式”。Lisp的其余部分可以在这些特殊形式的基础上进行迭代。我对ELisp不太熟悉,但常见的Lisploop功能是通过宏实现的。您可以扩展该语言——通常

我最近读了一本黑客和画家的书。作者说Lisp宏比其他语言的宏功能强大且特殊

我开始学习ELisp宏,但仍然不知道它有什么特殊用途?看不出它和C/C++宏之间的区别


有人能给我解释一下吗

> LISP宏允许您在比C++宏更深层的地方修改语言。Lisp宏是在编译阶段执行的代码片段,它们可以控制参数的计算

例如,Lisp基于编译器必须处理的25个“特殊形式”。Lisp的其余部分可以在这些特殊形式的基础上进行迭代。我对ELisp不太熟悉,但常见的Lisp
loop
功能是通过宏实现的。您可以扩展该语言——通常Lisp只有一种特殊的条件语句形式,其他所有的条件语句都是在Lisp的基础上实现的
defun
,这是用于定义函数的结构,我相信可以作为宏来实现

C++宏虽然功能强大,但由预处理器执行,这意味着它们的功能有限。Lisp宏是在编译环境中执行的,因此可以执行函数来确定如何重写输入,包括程序员定义的函数


这个回答相当复杂和模糊,所以希望有更多时间的人能够提供更好的回答。我和帕斯卡一样为我的回答冗长而含糊不清而道歉。

我认为最重要的几点是:

  • Lisp代码表示为列表,使用Lisp宏,您可以使用Lisp的所有列表处理功能(这是Lisp非常适合的功能,请记住Lisp代表列表处理)对其进行转换。(同源性)然而,C/C++预处理器宏仅仅是文本替换。也就是说,要执行更复杂的转换,您必须自己解析C/C++预处理器宏的输入(并且您通常无法访问这些语言中的解析器)。您不能使用所有的C/C++或任何手边的语言来转换代码。这些简单的宏工具似乎更适合于小缩写(或绕过类型系统、性能解决方案等),而不是真正的抽象。(并不是说不能将它们用于更复杂的任务,而是很快就会变得一团糟。)

  • Lisp语法也比通常的花括号语言规则得多。您不必担心优先级规则、中缀运算符或语句与表达式之间的区别

  • 与Lisp宏相比,据我所知,使用C/C++预处理器宏时,您无法轻松地在宏定义中使用宏,而无需跳转,因为预处理器只执行一次

  • (据我所知)在C/C++风格的预处理器宏中引入新符号并不容易。(您可以在CL风格的宏中使用
    gensym
    和围绕它构建的抽象,如
    和gensym
    等,还有卫生的宏系统,主要用于Scheme方言。)

  • Lisp中的反引号表达式是构建宏扩展到的代码的一种非常方便的填空方法

总之,使用Lisp宏进行元编程比使用C/C++预处理器进行元编程方便得多。在实践中,这意味着,即使是Lisp的相对新手也能够轻松地创建自己的循环结构或其他控制结构。有了更多的经验,编写更复杂的DSL也变得相对容易。与C/C++预处理器相比,在C/C++预处理器中,这些任务可能被认为是某种黑魔法,只为最勇敢的人保留

作为一个简单的示例,请尝试使用C/C++预处理器编写如下内容:

(defmacro bif ((var expression) then &optional else)
  `(let ((,var ,expression))
     (if ,var ,then ,else)))
它引入了一个新的控制结构
bif
(“binding if”),它对表达式求值,将其绑定到给定符号,然后有条件地执行
then
else
分支,并在范围内进行绑定。它可以正常嵌套并按预期工作。现在,任何一个Lisp程序员都可以很快写出这样的东西。由于这很容易,Lisp程序员在感到需要一个新的构造时通常会毫不犹豫——语言设计者和语言用户之间的障碍是模糊的


(即使使用C/C++预处理器编写,下一步,即编写类似Lisp的
cond
,或新的循环构造,也会很快变得复杂得多。)

请给出一个Lisp宏的示例,由于Lisp有许多构造,C++的宏世界几乎是无限的。你可以看到这里的文档:我使用<代码>(宏扩展所有)(BIF(x 5)(打印“OK”))(<代码)>但是获取:<代码>(BIF(x 5)(打印“OK”)(打印“坏”))/Boo>扩展错过了,如果是,为什么?HM,对我来说是:<代码>(宏扩展全部(bif(x 5)(打印“ok”)(打印“bad”))→
(LET((X 5))(如果X(打印“ok”)(打印“bad”))
。您的软件包中可能有一个坏版本的
bif
(打字错误或其他版本的错误?)。宏调用似乎找不到宏定义。当我将bif重命名为biff时,我非常确定我没有定义此宏:biff。如何修复它?我重新复制了您的宏定义,重试了它。这次收到错误消息:调试器输入了--Lisp错误:(无效函数(lambda((var表达式)then&optional else)(`(let)(\,var)(\,表达式))(if(\,var)(\,then)(\,else((var表达式)then&可选else)(`(let…)((x5)(打印“ok”)(打印“bad”))(bif(x5)(打印“ok”)(打印“bad”))nil)宏扩展((bif(x5)(打印“ok”)(打印“bad”))