Common Lisp宏和Forth元编程能力的比较

17

每个Common Lisp程序员都知道宏是一种强大的工具。除了不更改语言规范以外,Common Lisp宏还可以用于在Lisp顶部添加面向对象编程;读取宏是另一个具有令人费解能力的构造。

另一个允许元编程的程序是Forth。Forth使用“单词”和“生成单词”的方式略有不同。

我想知道,对于那些涉足过这两种语言的人来说,Common Lisp宏和Forth结构在广度/功率上是否可比较:前者能做到的后者能做到吗?或反之亦然?

当然,我的意思不是指这两种语言的图灵完备性:我所说的是它们的元编程能力。Metaprogramming C是图灵完备的,但只有愚蠢的人才会声明C宏与Common Lisp宏在功能上相当。


3
这个问题比之前的版本Lisp 和 Forth 宏[搁置]更加具体,这是好的。当然,现在那个问题已经有重新开放的投票了,而这个问题却有一个关闭的投票,所以关于哪个应该保持开放存在一些混淆。这个问题中你要寻找的东西更加清晰,但它仍然可能不适合主题,因为"比较问题不适合[Stack Overflow],因为可以发布回答没有限制。" - Joshua Taylor
5
这个关闭问题的原因是“范围过于广泛”,即“可能有太多的答案”,或者“好的答案需要超出这个平台所限定的字数限制”。这并不代表这是一个“糟糕”的问题,只是它不是一个很适合在 Stack Overflow 上发布的问题。比如说,这样的问题可能会更适合在 comp.lang.lisp 这个论坛上提问。 - Joshua Taylor
1
反对因“过于广泛”而关闭。例如回答:“在LANG1中,您无法实现已在LANG2中实现的foo,因为您缺少LANG1具有而LANG2没有的bar。” 在为什么有些问题被标记为“暂停”?中没有提到“答案过多”作为关闭问题的原因。 - user3750103
2
实际上,你链接的页面中已经有了答案:“过于宽泛 - 如果你的问题可以通过一本书来回答,或者有很多有效的答案,那么它可能对我们的格式来说太宽泛了。 可能有太多可能的答案,或者好的答案对于这种格式来说太长了。请添加细节以缩小答案集或隔离一个可以在几段落内回答的问题。 - Joshua Taylor
1
“除了改变语言规范之外,Common Lisp 宏还被用于在 Lisp 之上添加面向对象编程等功能。”这句话不太准确。例如,CLOS 不仅仅是宏,而且为此更改了各种语言设施的规范。 - Rainer Joswig
显示剩余2条评论
3个回答

10
在我看来,Common Lisp宏类似于Forth的立即词(immediate words)。(实际上,它们最类似于Lisp阅读器宏。)
它们都是过程式宏,即可以使用语言的全部功能。
它们都可以访问源代码输入。
它们都可以输出语言中可表达的任何内容。(例如,在Lisp中进行面向对象扩展,在Forth中进行基本控制流构造。)
主要区别可能在于,Forth“宏”输入是字符字符串,而Lisp宏操作解析树。

4
Lisp宏在S表达式上运作,我想这可能看起来像是解析树对于非Lisp程序员来说,但还是有所不同。 我提到这个区别是因为在几乎任何Lisp方言中,读取阶段在编译阶段之前,因此当Lispers编写宏时,他们将代码视为数据。 好极了,同构性!(由于[common-lisp]是您的顶级标签,因此您显然已经知道所有这些内容,但我认为其他读者也应该了解这种区别。) - C. K. Young
Forth的即时词也可以在单词级别而不是输入流级别上操作 - 这主要取决于实现提供的自定义点。它们还可以保持输入流不变。此外,使用[]分别切换编译关闭和打开,您可以动态定义“即时词”,即获取编译时常量等。顺便说一下,在Python中这很难做到,因此对我来说,Python和FORTH + LISP属于两个不同的类别。如果C++有一个公开的constexpr解析器API,那么Python更像C ++ ... - Kuba hasn't forgotten Monica

9
我是一个Forth实现者,对Forth有广泛的经验,有过半打的实现,解决了几百个projecteuler问题。我还做过一个小型面向对象的扩展(小到只有十几行代码)。
我在LISP方面的经验更多是在课程层面上,但我认为可以说LISP的元编程功能更加系统化,在实践中也更加强大。另一方面,Forth在语言转换方面表现出色,如果你的目标是产生与Forth完全不同、甚至无法被识别的东西,那么选择Forth是明智的。
在LISP中,构建抽象层次相对容易。而在Forth中,如果我想在由具有非平凡定义的对象定义的线性空间上定义一个矩阵...我会切换到Python。
原因对我来说也很明显。LISP的创造者是数学家,而Chuck Moore则是实用程序员的典范,从不浪费时间在理论问题上。
这种情况在以下方面得到延伸。LISP宏在Lisp的上下文中具有结构,并且至少暗示着与一般Lisp原则一致的含义。而Forth的即时词只是另一个程序,可以意味着和做任何事情,包括把它搞得一团糟。

在LISP、Python和FORTH上做了相当多的工作后,我想说FORTH的即时词汇可能具有最大的能力,并且能够实现高度表达特定领域语言。尝试在Python中连接到解析器输入流……即使在LISP中,这也不是一件容易的事情。顺便说一句,在FORTH中,复杂对象的矩阵表现得更好,因为您只需要支付实际需要的对象属性的价格——假设您的实现不仅仅是复制Python。在Python中,“object”的虚拟方法表是巨大的,并且是一个严重的扩展瓶颈。 - Kuba hasn't forgotten Monica
在FORTH中,即时词是编译器自定义点,类似于单个虚拟方法。从数学上讲,它们的语义相当明确,不难得出确定性的形式化 - 当然,每个实现的细节都有所不同,因为某些实现有效地提供了多个这样的虚拟方法来覆盖。但对于任何特定的实现,形式化即时词是不难的。 - Kuba hasn't forgotten Monica

3
抱歉如果下面的讨论似乎有些含糊不清,但需要说的东西太多了。
我只有Lisp的理论知识,没有实际操作经验。
另一方面,Forth可能(但通常情况下不会)在语言内部具有完整的元编程功能。但元编程是可以考虑和实现的,只是缺少一个连贯的语法。我认为在Lisp中也存在同样的情况。
我已经用包含在类似Forth语言的小范式中的非常干净的解决方案实现了这个可能性。为了使用元编程,我们应该能够引用我们所写的内容。因此,当我们编写一个立即执行的程序时:
bread eat

我们应该能够只是引用同一句话的意图而不必立即执行它,以便将来可以参考。可以通过写例如来实现这一点。
{ bread eat } 

上述短语可能会导致在堆栈上留下创建的对象。但是,由于我们创建了一个新词作为“{”和“}”,我们也有权引用它们。
因此,我们可以参考:
{ bread 

我们应该如何称呼它?一种尝试性的语法是:{{ { bread }}

如果我们给前面的短语命名为XXX,我们可以将初始短语写成:
XXX eat }

上面的短语应该正确地将其留在堆栈上。
{ bread eat }

由于我不知道我说的话是否完全符合您的要求,因此简单地说,通过上述推理及其在Forth中的实现,每个单词都会获得执行级别,这定义了单词的元编程级别。
显然,我们有第一个无限级和每个连续级。因此,执行级别基于数学无限大。
我已经在某种Forth中实现了上述内容,在第一级别(低于无限大)中一切顺利。例如,我能够更改以下语法:
{ bread eat } { tomatos eat } x 3 = if 

into:

{ bread eat | tomatos eat } x 3 = if 

这是通过将|定义为} {来完成的,如下所示:
{{ } { }} "|" define

或者,如果你更喜欢这样说:
2{ } { 2} "|" define 

上述方法将元语言插入到具有正确语法的语言中,并使其成为语言。
因此,在我看来,Lisp和Forth都具有元编程的可能性,但都缺乏将其作为语言集成部分的可能性。
我在napl.wikispaces.com上有更多详细信息。

1
我只有Lisp的理论知识,没有实践经验。... 我认为Lisp也会遇到同样的情况。 - Rainer Joswig
我会将{ bread }称为{ '{ compile, bread }' }。我非常喜欢在Forth中用{ }来包含短语。那些C语言的人在发明符号表示法时真是太明智了。 - undefined

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