为什么 Lisp 的所有动态特性都可以静态编译,而 Python 却不能(不会丢失所有动态特性)?
4 回答
没有什么可以阻止 Python 的静态编译。它的效率有点低,因为 Python 揭示了更多可变的局部范围,此外,为了保留一些动态属性(例如 eval),您需要将编译器包含在已编译的程序中,但也没有什么能阻止这一点。
也就是说,研究表明,大多数 Python 程序虽然在静态分析下是动态的,但在运行时却是相当静态和单态的。这意味着运行时 JIT 编译方法在 Python 程序上工作得更好。有关将 Python 编译为机器代码的方法,请参阅 unladen-swallow、PyPy、Psyco。还有 IronPython 和 Jython,它们使用最初用于静态语言的虚拟机将 Python 编译成机器码。
对于它的价值,Python 脚本在执行时被编译成 .pyc 文件,请参阅“编译的”Python 文件。
您还可以使用py2exe等工具将 Python 程序编译为可执行文件。
实际上,没有什么可以阻止您静态编译 Python 程序,只是到目前为止还没有人编写过这样的编译器(我个人认为 Python 的运行时与 CL 相比非常容易)。
您可以说差异在于诸如“实际编写编译器花费了多少时间以及该语言是否具有如何编写编译器的正式规范”之类的细节。
让我们解决这些问题:
- Lisp 编译器已经发展了 40 多年,如果不是更早的话,工作可以追溯到 70 年代(我不确定我的日期,太懒太谷歌了)。这创造了大量关于如何编写编译器的知识。OTOH,Python 名义上被设计为“教学语言”,因此编译器并不那么重要。
- 缺乏规范 - Python 没有指定语言确切语义的单一来源。当然,您可以指向PEP文档,但它仍然不会改变唯一真正的规范是主要实现CPython的来源这一事实。其中,nota bene,是一种简单的编译器(转换为字节码)。
至于是否有可能——Python使用非常简单的结构来处理符号等,即它的字典。您可以将它们视为程序的符号表。您可以标记数据类型以识别原始数据类型,并根据存储的命名和内部结构获取其余数据类型。其余的语言也相当简单。唯一缺少的是实现它并使其正确运行的实际工作。
Python 可以“编译”,其中编译被视为从一种图灵完备语言(源代码)到另一种(目标代码)的翻译。然而在 Lisp 中,对象是汇编,这在理论上用 Python 是可行的(经过验证)但不可行。
然而,真正的原因是不那么扁平化。Lisp 在很多方面都是一种革命性的语言,它在方言中开创了我们今天习惯的编程语言的许多特性。然而,在 Lisps 中,它们只是从语言的基础逻辑“遵循”。受 lisps 的原始表达能力启发的语言(如 JavaScript、Ruby、Perl 和 Python)必须被解释,因为在具有“类似 Algol 的语法”的语言中获得这些功能非常困难。
Lisp 从“同质”中获得这些特性,lisp 程序和 lisp 数据结构之间没有本质区别。Lisp 程序是数据结构,如果您愿意,它们是这样的 S 表达式中程序的结构描述,因此编译后的 lisp 程序可以有效地“解释自身”,而不需要词法分析器和所有这些东西,lisp 程序可以只是可以看作是解析树的手动输入。这需要一种许多人发现使用起来违反直觉的语法,因此有很多尝试将范式的原始表达能力转换为更易读的语法,这意味着编译它是不可行的,但并非不可能朝向组装。
此外,将 Python 编译为程序集可能会比在虚拟机上“半解释”它更慢且更大,python 中的许多功能取决于句法分析。
上面虽然是由一个巨大的 lisp 粉丝写的,但请记住这种利益冲突。