【问题标题】:Comparison of Common Lisp macros and Forth metaprogramming capabilitiesCommon Lisp 宏和 Forth 元编程能力的比较
【发布时间】:2014-08-08 13:09:48
【问题描述】:

每个 Common Lisp 程序员都知道宏是一个强大的工具。通用 Lisp 宏已被用于在 Lisp 之上添加面向对象而不更改语言规范;读取宏是另一种具有思维弯曲功能的构造。

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

我想从涉足这两种语言的人那里知道,常见的 lisp 宏和 forward 构造是否在广度/功能上具有可比性:是否有一些你可以用前者做而你不能用后者做的事情?反之亦然?

当然,我不是在谈论两种语言的图灵完备性:我在谈论metaprogramming 能力。 C 是图灵完备的,但只有傻瓜才会说 C 宏在功能上与 Common Lisp 相当。

【问题讨论】:

  • 这比之前的版本Lisp and Forth macros [on hold]具体多了,很好。当然,现在 那个 问题已经重新开始投票,而这个问题已经接近投票,所以对于哪些应该真正保持开放存在一些混淆。在这个问题中您要寻找的内容要清楚得多,但它仍然可能是题外话,因为"comparison question are a poor fit for [Stack Overflow], because there are no bounds to the answers which can be posted to them."
  • 太宽泛的密切原因在这里适用:“要么可能的答案太多,要么对于这种格式来说,好的答案太长了。 "这根本不是一个的问题。它不是特别适合 Stack Overflow。例如,这个问题在 comp.lang.lisp 中可能很棒。
  • 特定的子问题,“有没有你可以用前者做而你不能用后者做的事情?反之亦然?”可能是这里最具体的。它仍然可能承认太多的答案,但如果有一些事情可以做而另一个不能,那么可能会给出一个相对规范的答案。
  • 反对因过于宽泛而关闭。示例答案:“在LANG1 中,您无法实现foo,它已在LANG2 中实现,因为您缺少barLANG1 有而LANG2 没有。”在Why are some questions marked "on hold"? 中没有提及“太多答案” 作为应该关闭问题的原因。
  • 实际上,它就在您链接到的页面中:“太宽泛 - 如果您的问题可以用整本书来回答,或者有很多有效的答案,那就是对于我们的格式可能过于宽泛."

标签: lisp common-lisp metaprogramming forth gforth


【解决方案1】:

在我看来,Common Lisp 宏类似于 Forth 立即字。 (实际上,它们与 Lisp 阅读器宏最相似。)

  • 它们都是过程宏,即可以使用语言的全部功能。

  • 他们都可以访问源代码输入。

  • 他们都可以输出任何可以用语言表达的东西。 (例如,Lisp 中的面向对象扩展,或 Forth 中的基本控制流结构。)

主要区别可能在于 Forth“宏”输入是字符串,而 Lisp 宏在解析树上运行。

【讨论】:

  • Lisp 宏适用于 S 表达式,我想这对于非 Lispers 来说可能看起来像解析树,但仍然如此。我提到这个区别是因为在几乎任何 Lisp 方言中,读取阶段都在编译阶段之前,因此 Lispers 在编写宏时将代码 视为 数据。耶同音! (因为 [common-lisp] 对你来说是一个顶级标签,所以你清楚地知道所有这些,但我觉得这里的其他读者也应该理解其中的区别。)
  • 第四个立即字也可以在字级别而不是输入流级别进行操作——这主要取决于实现提供的定制点。他们还可以保持输入流不变。此外,使用[] 分别关闭和打开编译,您可以动态定义“立即字”,即获取编译时常量等。顺便说一句,在 Python 中非常困难,所以对我来说,Python 和 FORTH + LISP 属于两个不同的类。 Python 更像是 C++,如果它有一个暴露的 constexpr 解析器 API...
【解决方案2】:

对不起,如果下面的讨论看起来有点模糊,但要说的太多了。

我只有 Lisp 的理论知识,没有动手能力。

另一方面,Forth 可以(但普通的 Forth 没有)语言内部的完整元编程。但是元编程是可以考虑和可能的,但没有连贯的语法。我认为在 Lisp 中也会发生同样的情况。

我已经实现了一个非常简洁的解决方案,其中包括在类似 Forth 的小型语言范式中的可能性。为了进行元编程,我们应该能够参考我们所写的内容。所以当我们写一个程序要立即执行时:

bread eat

我们也应该能够在意图中引用同一个短语,而不是执行它以保留它以供以后参考。这可以通过写作来完成,例如

{ bread eat } 

上面的短语可能会导致将创建的对象留在堆栈上。但是,当我们创建了一个新词 {} 时,我们也有权引用它。

所以,我们可以参考:

{ bread 

我们怎么能提到那个?暂定语法为:{{ { bread }}

如果我们将名称 XXX 赋予前一个短语,我们可以将初始短语写为:

XXX eat }

上面的短语应该可以正确地留在堆栈上

{ bread eat }

由于我不知道我所说的是否正是您要寻找的内容,所以只要说通过上述推理及其在 Forth 中的实现就足够了,每个单词都有一个执行级别,它定义了哪个是元编程级别这个词。

显然,我们有第一个无限级别和每个后续级别。所以执行级别是基于数学无穷大的。

我已经在一种 Forth 中实现了上述内容,并且在第一级(无限远)一切正常。因此,例如 a 能够更改以下语法:

{ bread eat } { tomatos eat } x 3 = if 

进入:

{ bread eat | tomatos eat } x 3 = if 

这是通过将| 定义为} { 来完成的:

{{ } { }} "|" define

或者如果你更喜欢它:

2{ } { 2} "|" define 

上面的方法以正确的语法将元语言放入语言内部并使其成为语言。

所以在我看来,Lisp 和 Forth 都有元编程的可能性,但作为语言的集成部分,两者都缺乏这种可能性。

我在napl.wikispaces.com 上有更多详细信息。

【讨论】:

  • 我对Lisp只有理论知识,没有动手。 ...我认为 Lisp 中也会发生同样的情况。
【解决方案3】:

我是一名 Forth 实现者,在 Forth 方面拥有丰富的经验,有六种实现,数百个 projecteuler 问题。我还做了一个小的面向对象的扩展(小,即十几行左右)。 我在 LISP 方面的经验更多是在课程层面,但我认为可以说 LISP 的元编程工具更系统,在实践中更强大。

在 LISP 的抽象之上构建抽象相对容易。在 Forth 中,如果我想在由具有非平凡定义的对象定义的线性空间上定义一个矩阵。我切换到 Python。

原因也很明显,至少对我来说是这样。 LISP 的创建者,其中数学家,而 Chuck Moore 是实际程序员的终极典范,从不将时间浪费在理论问题上。

这通过以下方式延伸到这个问题。 lisp 宏在 Lisp 上下文中具有结构,并且至少暗示了符合一般 lisp 原则的含义。 Forth 直接词只是另一个程序,可以表示和做任何事情,包括用它做一顿狗晚餐。

【讨论】:

  • 在 LISP、Python 和 FORTH 方面做了大量工作后,我想说 FORTH 直接词可能是最强大的,并且可以实现高度表达的领域特定语言。尝试在 Python 中修补解析器输入流……即使在 LISP 中,也不是胆小的人。顺便说一句,复杂对象的矩阵在 FORTH 中表现得更好,因为您只需为实际需要的对象属性付出代价——假设您的实现不只是复制 Python。在 Python 中,object 的虚方法表非常庞大,是一个严重的扩展瓶颈。
  • 在 FORTH 中,立即字是类似于单个虚拟方法的编译器自定义点。在数学上,它们的语义是非常明确的并且不难最终形式化 - 当然,每个实现的细节都会有所不同,因为一些实现有效地提供了多个这样的虚拟方法来覆盖。但是对于任何特定的实现,都不难确定直接的词是什么。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-30
  • 2019-11-17
  • 2011-03-08
  • 1970-01-01
  • 2016-02-17
相关资源
最近更新 更多