5

[译]Lisp、Smalltalk 和对称性的力量

 2 years ago
source link: http://wwj718.github.io/post/%E7%BC%96%E7%A8%8B/lisp-smalltalk-and-the-power-of-symmetry/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

[译]Lisp、Smalltalk 和对称性的力量

2022-08-12

原文: Lisp, Smalltalk, and the Power of Symmetry

和许多黑客一样,我第一门真正爱上的编程语言是 Lisp。保罗·格雷厄姆(Paul Graham)激发了我对这种语言的探索,他是个特别的 Lisp 倡导者,写了很多关于 Lisp 的文章,谈论是什么让它与众不同。那么,是什么让 Lisp 与众不同呢?尽管 Lisp 发明于 1958 年,是世界上第二古老的高级编程语言,为什么 Lisp 仍然是现存最强大、最灵活、最简洁的编程语言之一?

保罗·格雷厄姆的回答是宏(macro)

许多语言都有一个叫做宏的东西。但 Lisp 的宏是独一无二的。[…]
Lisp 代码是由 Lisp 数据对象组成的。这并不是在琐碎的意义上说,源文件包含字符串,字符串是语言支持的数据类型之一。Lisp 代码,在被解析器(parser)读取后,是由你可以遍历的数据结构组成的。
如果你了解编译器(compilers)是如何工作的,实际发生的事情并不是 Lisp 有一个奇怪的语法,而是 Lisp 根本没有语法。当其他语言被解析时,你在编译器内生成的解析树中编写程序。但是这些解析树对于你的程序来说是完全可以访问的。你可以写程序来操作它们。在 Lisp 中,这些程序被称为宏。它们是编写程序的程序。

保罗的论点里,隐藏着一个有趣的暗示。他说,宏使 Lisp 变得强大,因为它们允许你编写本身就能编写程序的程序。但是,这就是宏,而不是使宏成为可能的东西–Lisp 的宏不是它强大的原因,而是它的一个症状。使 Lisp 强大的不是它的宏,而是这一事实: Lisp 运行在编写它的上下文中。至始至终都是 S-表达式。这导致了一种有趣的可能性:是否有其他方法来实现类似的功能?宏是让程序编写程序的唯一方式吗?还是有其他的方式?

当我在大学学习计算机语言时,我们在 Lisp 之后研究的第二种语言是 Smalltalk。我对 Lisp 的力量和灵活性印象深刻,所以那天我的第一个问题是:“Smalltalk 有宏吗?” 教授在思考了一会儿之后,回答说:“Smalltalk 不需要宏”。嗯?Smalltalk 不需要宏?为什么不需要?那它有什么?我花了三年时间才搞清楚。Smalltalk 不需要宏,因为它有类(class)。

将面向对象的类与 Lisp 的宏相提并论似乎有些奇怪。类和类结构不是出了名的僵化脆弱,而且容易产生意大利面条代码吗?这些不都是 Lisp 宏的反面吗?

当 OOP 指的是 “我在设计这个类的层次结构时在想什么” 时,面向对象编程(“OOP”)的一般风味确实如此。Java、C++、甚至 Python 等语言似乎认为 “面向对象” 主要意味着 “类和继承”。这有点像说 “开车” 主要意味着 “按钮和踏板”。大多数这些语言都忽略了一点,那就是 Smalltalk 的类系统,就像 Lisp 的宏系统一样,是语言中已经存在的力量的一个症状,而不是其原因。如果它不具备这些功能,那么自己添加这些功能并不难。

如果没有 Smalltalk 的底层基础,类的继承只不过是一种代码重用的工具。在这类工具,它既不是唯一也不一定是最好的。Smalltalk 对象系统的真正力量(包括类),不是继承,而是反射(reflection)。正如 Lisp 宏之所以强大,是因为它们可以对任何 Lisp 代码进行操作,包括它们自己,Smalltalk 类之所以强大,是因为它们本身就是对象。Smalltalk 和 Lisp 一样,都是在其编写的上下文中运行的一路往下都是对象

Lisp 之所以强大,是因为所有的 Lisp 程序也是 Lisp 数据–所有可以运行的东西都可以被写成/读S-表达式。Lisp 中的宏只是当你归纳应用这种关系时发生的事情:它们是操作数据的代码,而数据本身就是代码。

Smalltalk 之所以强大,是因为所有的 Smalltalk 数据都是程序–所有的信息都是由运行的、活生生的对象体现出来的。Smalltalk 中的类编程只是操作本身就是数据的程序–这是 Lisp 哲学的反面,但最终结果是一样的。正是它使 Smalltalk 调试器能够冻结、剖析、修改和恢复正在执行的程序。它使浏览器(browser)能够立即找到所有响应给定消息的对象,或找到给定对象的所有超类和子类,或找到给定类的每个运行实例。这就是为什么 Smalltalk 集成开发环境不仅仅是用这种语言编写的,它实际上就是这种语言。

正如保罗在前头提到的,Lisp 实际上没有语法: 因为 Lisp 源代码、运行中的 Lisp 代码、Lisp 数据 表达形式相同,三者是可以互换的。程序可以改写数据,而这些数据可以作为程序运行,这些程序可以改写数据…

Smalltalk 比 Lisp 更进一步:并不是说 Smalltalk 的源代码没有语法,而是 Smalltalk 没有源代码。毕竟,“源代码” 只是意味着 “没有运行的程序”,而没有运行的 Smalltalk 程序是不存在的。因为在 Smalltalk 中,除了 “运行的数据”(对象)之外,别无他物,所以在 Smalltalk 中没有数据和程序的区别。数据(对象)可以编写程序(对象),程序(对象)可以编写数据(对象)…

所以 Lisp 宏并不是让程序写程序的唯一方式。一种语言要允许这样做,似乎唯一需要的是程序和数据之间普遍存在的对称性。如果一种语言允许程序和数据被视为同一事物,那么这种语言就会变得容易和无限扩展–一种上帝的语言。事实证明,S-表达式并不是做到这点的唯一方法–你也可以用对象来做到这点。我想知道是否还有我们尚未尝试过的其他方法,能做到这点呢?


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK