什么是元循环解释器的确切定义?

20

一个用C编写的C编译器或用PHP编写的PHP解释器是否可被称为“元环”的合法?这个定义仅适用于特定类型的语言,比如Lisp吗?简而言之,一个被称为元环的解释器应满足什么条件?


1
顺便提一下,这是PLAI教材中讨论的问题之一(请参见www.plai.org)。阅读该教材可能比阅读维基百科更好。 - Eli Barzilay
4个回答

28

元循环解释器是一种用同一语言的(可能更基础的)实现编写的解释器。通常这样做是为了尝试向语言中添加新功能或创建不同的方言。

之所以将这个过程与Lisp联系在一起,是因为这篇高度清晰的论文《解释器的艺术》展示了几个基于Scheme的元循环解释器。(该论文是书籍SICP的核心,其第四章介绍了其他创造惰性计算Scheme的元循环解释器.)

这在“同像”语言(一种代码可以在运行时作为数据进行操作的语言)中,例如Lisp、Prolog和Forth中要容易得多。

至于您直接的问题——C编译器根本不是解释器。用自己的语言编写的编译器是“自举”的,这是类似的属性,但更相关于引导程序。用PHP编写的PHP解释器可能不符合条件,因为在此过程中你可能需要重新实现大量的语言功能。传统元循环解释器的主要优点是没有必要——您可以插入现有的解析器、垃圾回收等,并只编写具有不同语义的顶层求值器。在Scheme或Prolog中,这通常只需要不到一页的代码。


3
这个与Lisp有关的原因是因为McCarthy(你可能听说过他)用Lisp语言描述了Lisp评估的过程。 - Rainer Joswig
4
尽管最初的Lisp是在纸上定义的(在实现之前),但AotI / SICP可能更直接地推广了这个想法和术语,这也是问题所在。此外,我确实听说过他。那真的有必要吗? - silentbicycle
2
无论你想说什么,这个术语都通过麦卡锡的著名论文与Lisp联系在一起。很高兴17年后Scheme论文和一些书籍接受了这个想法。 - Rainer Joswig
6
艾伦·凯说:“……那是我在研究生阶段大有启发的时刻——当我终于理解了 Lisp 1.5 手册第13页底部半页代码实际上就是 Lisp 本身时。这些代码就是‘软件世界的麦克斯韦方程式’!这几行代码涵盖了整个编程世界。” - Rainer Joswig

7
以下是相关内容的翻译:

以下内容摘自维基百科关于元循环页面:

元循环求值器是自解释器的特例,其中父解释器的现有功能直接应用于被解释的源代码,无需额外的实现。

因此,在这两种情况下答案都是否定的:

  • C语言编译器不是解释器(求值器)。它将程序从一种形式转换为另一种形式而不执行它。
  • 用PHP编写的(假设的)PHP解释器将是自解释器,但不一定是元循环。

4
为了补充以上答案:http://www.c2.com/cgi/wiki?MetaCircularEvaluator 在Lisp中,通过调用“eval”实现了“eval”。但是,许多其他语言中没有“eval”(如果有的话,它具有不同的语义),因此必须编写一个全新的语言系统,其中详细说明“eval”的算法-这在元循环情况下是不必要的。这就是MetaCircularEvaluators的魔力:它们反映了它们所可能出现的语言的基本魔力。

-1

据我所知,元循环解释器是一种可以解释自身的解释器。

编译器只翻译代码,不执行它。

任何图灵完备语言在数学上都能模拟任何逻辑计算,因此这里有一个使用Python的例子。你可以使用PyPy而不是使用CPython将此代码翻译为CPU指令并执行它。后者是自举的, 因此满足了一些人用来定义元循环解释器的任意标准。

"""
Metacircular Python interpreter with macro feature.
By Cees Timmerman, 14aug13.
"""

import re

def meta_python_exec(code):
    # Optional meta feature.
    re_macros = re.compile("^#define (\S+) ([^\r\n]+)", re.MULTILINE)
    macros = re_macros.findall(code)
    code = re_macros.sub("", code)
    for m in macros:
        code = code.replace(m[0], m[1])

    # Run the code.
    exec(code)

if __name__ == "__main__":
    #code = open("metacircular_overflow.py", "r").read()  # Causes a stack overflow in Python 3.2.3, but simply raises "RuntimeError: maximum recursion depth exceeded while calling a Python object" in Python 2.7.3.
    code = "#define 1 2\r\nprint(1 + 1)"
    meta_python_exec(code)

用C编写的C编译器不是元循环求值器(MetaCircularEvaluator),因为编译器必须为每个构造指定非常详细和精确的语义。编译器使用目标语言编写并不会有任何帮助;相同的算法可以被翻译成Pascal、Java、Ada或Cobol,仍然是一个完美的C编译器。
相比之下,Lisp的元循环解释器无法翻译成非Lisp语言。没错,就是“无法”——至少不能用简单的一对一方式。Lisp用Lisp编写实现了“eval”通过调用“eval”。但是,在许多其他语言中,没有“eval”(如果有,它具有不同的语义),因此必须编写完全新的语言系统,其中给出了“eval”的详细算法,这在元循环情况下是不必要的。
而这正是元循环求值器的魔力所在:它们反映了它们可能存在的语言的基础魔力。

1
这不是元循环解释器。它甚至不是解释器,而是一个预处理器。 :) - Tobias
1
exec和相关函数虽然是元级别的行为,但并不构成元循环解释器。在没有任何元级别设施的语言中,您可以制作元循环解释器。关于“元循环”的事情是:用语言A编写的语言A的解释器。例如,Pascal用Pascal编写,Basic用Basic编写,Smalltalk用Smalltalk编写。使用exec只是将其传递给主机Python,并不构成Python的新实现。pypy是一个元循环Python,您应该看一下! - Tobias
1
元循环性是关于解释器(或编译器)的。您的代码既不是解释器也不是编译器,因此不是元循环的。但是,它正在使用元编程。 - Tobias
1
在Lisp/Scheme中,它不是“用Lisp编写的通过调用'eval'实现'eval'”的Lisp,当第一个eval与第二个eval不同时。被调用的eval不应与Python的exec混淆;eval是由元循环解释器实现的,而不是主机语言的解释器。 - Tobias
1
虽然Lisp元循环求值器将许多方面委托给其主机Lisp,但它确实执行了实际的_解释_。在这里使用Python的“exec”并不是那样。 - Tobias
显示剩余17条评论

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