Lisp宏特殊用法?

时间:2012-05-10 14:03:56

标签: c++ macros lisp

我最近读了黑客和画家的书。作者说Lisp宏比其他语言的宏非常强大和特殊。

我开始学习ELisp的宏,但还是看不出它的特殊用法呢?看不出它和C / C ++宏之间的区别。

有人可以帮我解释一下吗?

2 个答案:

答案 0 :(得分:4)

我认为最重要的一点是:

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

  • Lisp语法也比通常的大括号语言更常规。您不必了解优先规则,中缀运算符或语句和表达式之间的区别。

  • 与Lisp宏相比,据我所知,使用C / C ++预处理器宏,你不能轻易地在宏定义中使用宏而不跳过箍,因为预处理器只进行一次传递。 p>

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

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

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

作为一个简单的例子,尝试使用C / C ++预处理器编写类似的东西:

(defmacro bif ((var expression) then &optional else)
  `(let ((,var ,expression))
     (if ,var ,then ,else)))

它引入了一个新的控制结构bif(“binding if”),它控制表达式,将其绑定到给定的符号,然后有条件地执行thenelse分支。范围内的约束。它正确嵌套并按预期工作。现在,像这样的事情可以由任何Lisp程序员立即编写。由于它非常简单,Lisp程序员在感觉需要新构造时通常会毫不犹豫 - 语言设计者和语言用户之间的障碍模糊不清。

(即使有人设法使用C / C ++预处理器来编写它,下一步,即编写类似Lisp的cond或新的循环结构,将会变得更加复杂。)

答案 1 :(得分:3)

Lisp宏允许您在比C ++宏更深层次上修改语言。 Lisp宏是在编译阶段执行的代码片段,它们可以控制对其参数的评估。

作为一个例子,Lisp基于编译器必须处理的~25“特殊形式”。 Lisp的其余部分可以在这些特殊形式之上迭代存在。我对ELisp并不熟悉,但Common Lisp loop功能是通过宏实现的。你可以扩展语言 - 通常Lisps只有一个特殊形式的条件,而所有其他的都是在Lisp中实现的。我相信defun,这是用于定义函数的结构,可以实现为宏。

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

这种反应相当复杂和模糊,所以希望有更多时间的人能够提供更好的回答。我为Pascal做了道歉,因为这个答案很长而模糊。