小语言才是编程的未来 (小语言才是编程吗)

小语言才是编程的未来 (小语言才是编程吗)

我坚信,“小语言”——设计用来解决非常具体的问题——是编程的未来,特别是在阅读了 Gabriella Gonzalez 的著作《编程历史的终结》并观看了 Alan Kay 的演讲之后。你也应该看看,因为它们都很棒。下面,我会解释下我所说的“小语言”是什么,以及为什么它们很重要。

什么是“小语言”

我认为,“小语言”这个词是 Jon Bentley 在其同名文章“小语言”中创造的,他给出了以下定义:小语言是专门针对特定问题领域的语言,常规语言提供的许多特性它都没有。

例如,SQL 是一种描述数据库操作的小语言,正则表达式是一种用于文本匹配的小语言,是一种用于配置管理的小语言等。这类语言还有其他一些名称,如领域特定语言(DSL)、面向问题语言等等。

然而,我喜欢“小语言”这个词,部分原因是“DSL”这个词已经承载了太多的东西:从提供流体接口(Fluent Interface)的库到像 SQL 这样的成熟查询语言,还有就是“小语言”突出了它们“小”的特点。

为什么我们需要小语言?

在软件工程社区,我们真正遇到的一个问题是:随着应用程序复杂性的增加,其源代码的大小也会增加。然而在很大程度上,我们理解大型代码库的能力仍然没变。根据 Sourcegraph 公司 2020 年的一项调查(大代码的出现),大多数受访者表示,他们代码库的规模导致了以下一个或多个问题:

更糟糕的是,应用程序似乎在以惊人的速度增长:在 Sourcegraph 的调查中,大多数受访者估计,他们的代码库在过去十年中增长了 100-500 倍。举个例子,Linux 内核在 1992 年的时候是从大约 1 万行代码开始的,20 年后,它的体量约为 3000 万行。

这些代码是从哪里来的?“更多的功能”不足以解释这种代码量的增长。相反,我认为这与我们开发软件的方式有关。向程序中添加新功能的一般方法是将它们堆叠在已有的功能上,这与构建金字塔的方式没有什么不同。问题是,就像金字塔一样,后面每一层所需要的砖都比上一层多。

逆势而动

你真的需要数百万行代码才能创建一个现代操作系统吗?2006 年,Alan Kay 和他在项目中的合作者开始向这一假设发起挑战:

Dr. Kay 提到的麦克斯韦方程组是一组描述电磁学、光学和电路学的方程组。很酷的一点是,尽管涉及的范围很大,但它们却非常简洁:

它们如此简洁的一个原因是使用了符号(如∇)描述向量计算操作。需要注意的是,Del 并不是一个真正的运算符——它更像是一种简写,为的是使向量计算中的一些方程更容易处理。

是否有可能为编程创造出同等的 Del 符号呢?就像 Del 可以帮助我们使向量运算更易于管理一样,是否有符号可以以同样的方式帮助我们推断程序?这个问题是推动 STEPS 项目的“强大想法”之一:

其思想是:当你开始在应用程序中寻找模式时,就可以用一种小语言对它们进行编码——这种语言让你可以用一种比其他抽象方法更紧凑的方式来表示这些模式。这不仅可以防止应用程序不断变大的趋势,而且在实际的开发过程中还会使用代码库

我觉得,STEPS 项目一个特别令人印象深刻的成果是,这是一种描述图形渲染与合成的小语言。其目标是使用 Nile 实现与(一种用于各种自由软件项目的开源渲染器,有大约 44000 行代码)同等的功能,但 Nile 代码大约只有 300 行。

为什么不用高级语言?

可能有人会问,为什么不能发明一种更高级的通用语言呢?就我个人而言,我相,通用语言的表达能力已经到了回报递减的阶段。如果有更高级的语言,那它会是什么样子呢?以 Python 为例,它非常高级,看起来已经很像伪代码了。

通用语言的问题是,你仍然需要将问题转换为算法,然后用目标语言表达这个算法。高级语言非常擅长描述算法,但除非 是实现算法,否则这只是附带的复杂性。

写这篇文章时,我想起了一个关于 Donald Knuth 的故事:Jon Bentley 邀请 Knuth 在其专栏《编程珠玑》中展示他的编程风格;他还邀请 Doug McIlroy 对 Knuth 的项目进行评论。其任务是计算给定文本中的词频。

Knuth 的解决方案是用 WEB 精心编写的,这是他自己的 Pascal 编程变体。他甚至还加入了一个专门用于记录单词数量的数据结构,所有这一切用了不到 10 页代码。虽然 McIlroy 毫不犹豫地称赞了 Knuth 解决方案的精巧,但他对程序本身并不是很满意。作为评论的一部分,他用 Shell 脚本、Unix 命令和小语言编写了自己的解决方案:

tr -cs A-Za-z '\n' |
复制代码

虽然对于非 Unix 骇客来说,这段代码可能读起来有点困难(McIlroy 可能也会承认这一点,因为他认为提供一个带注释的版本比较合适),但可以说,与 10 页的程序相比,这个总结性的回复无疑更容易理解。

Unix 命令是为操作文本而设计的,这就是为什么用它可以编写出如此紧凑的单词计数程序——是不是可以将 Shell 脚本看成是文本操作的“Del 表示法”呢?

少即是多

上面的 Unix 命令示例说明了小语言的另一个特征:语言功能较弱、运行时功能较强。Gonzalez 在《编程历史的终结》一书中指出了如下趋势:

正则表达式和 SQL 只能分别用于表达文本搜索和数据库操作。这与 C 语言形成了鲜明的对比,C 语言没有运行时,你可以用它表达任何在冯·诺依曼体系结构上可能的东西。像 Python 和 Haskell 这样的高级语言介于两者之间:它们帮你完成内存管理,但你仍然可以使用图灵完备语言的全部功能,也就是说,你可以表达任何可能的计算。

与 C 语言相比,小语言处于能谱的另一端:不仅计算机的体系结构被抽象了,其中一些语言还限制了你可以表达的程序的种类——它们在设计上就是图灵不完备的。这听起来可能非常有局限性,但实际上,它为优化和静态分析打开了一个全新的可能性维度。而且,就像抽象掉内存管理可以消除一整类 Bug 一样,抽象掉尽可能多的算法工作,也有可能消除更多的 Bug。

静态分析

功能不那么强大的语言更容易推理,并且可以提供比通用语言更强的保证。例如,是一种用于生成配置文件的全函数式编程语言。因为你不想冒部署脚本崩溃的风险或者把它们放入无限循环,Dhall 程序可以保证:

第一点是通过不抛出异常来实现的;任何可能失败的操作(例如获取一个可能为空的列表的第一个元素)都返回一个 Optional 结果,该结果可能包含也可能不包含值。第二个点——保证终止——是通过不允许递归定义实现的。在其他函数式编程语言中,递归是表达循环的主要方式,但在 Dhall 中,你必须依赖于内置的函数。缺少一般的循环结构也意味着 Dhall 不是图灵完备的;但因为它不是一种通用编程语言,所以它不需要是完备的(不像 CSS)。

如果语言很小,就更容易推理了。例如,对于任意一个 Python 程序,都很难确定它有没有副作用,但在 SQL 中就很简单——只需检查查询是否以 SELECT[5]开始。

对于 Nile,STEPS 团队认为需要一个图形化调试器[9]。Bret Victor(是的,就是那个做过“原则性发明”演讲的 Bret Victor)发明了一个工具,它可以告诉你在屏幕上绘制特定像素所需的 。你可以在 YouTube 上观看Alan Kay的演示,也可以自己尝试一下。因为 Nile 是一种很容易推理的小语言,所以才可能有像这样的工具——想象一下,尝试用 C++编写的图形代码做同样的事情!

速度追求

功能更强大的编程语言不仅会增加 Bug 的可能性,还会对性能造成不利影响。例如,如果一个程序不是用算法表达的,那么运行时就可以自由选择自己的算法;如果我们能证明它们生成的结果相同,就可以用速度较慢的表达式代替速度较快的。

例如,SQL 查询并不规定一个查询应该如何执行——数据库引擎可以自由使用它认为最合适的任何查询计划,比如,它是应该使用索引,索引组合,还是直接扫描整个数据库表。现代数据库引擎还收集列的值分布信息,因此,它们可以动态选择统计学上最优的查询计划。如果查询是用算法的方式描述的,就不可能这样了。

使语言如此紧凑的“秘密武器”之一是,这是一种用于图形渲染的即时编译器。从团队和团队的讨论中可以清楚地看到,Cairo 的很多代码都是专门用于像素合成操作的手工优化;理论上,这些工作可以交给编译器。Cairo 团队的 Dan Amelang 自愿实现了这样一个编译器,也就是。这意味着图形管道中的优化工作可以从渲染内容的纯数学描述中分离出来,使得 Nile 的运行速度可以像最初手工优化的 Cairo 代码一样快。

小语言,大潜力

那么,STEPS 项目发生了什么呢?他们最终得到的是相当于“3 立方英里判例法”的代码,还是设法创建了一个小到可以印在 T 恤上的操作系统?STEPS 的最终结果是 KSWorld,这是一个完备的操作系统,包括文档编辑器和电子表格编辑器,代码最终有大约 17000 行[10]。虽然要印下所有这些代码需要一件非常大的 T 恤,但我仍然认为这很成功。

KSWorld 的创建似乎可以证明小语言的巨大潜力。然而,仍有许多未解之谜,例如:这些小语言相互之间应该如何交互?是否应该将它们编译成通用的中间表示形式?或者同时存在多种不同的运行时并通过通用协议(例如 UNIX 管道或 TCP/IP)相互通信?或者每种语言都足够小,可以用各种不同的宿主语言重新实现(比如正则表达式)?又也许,未来的道路会结合所有这些方法?无论如何,我都相信,我们需要想出一种不同的软件构建方法。也许小语言会成为这个故事的一部分,也许它们不会——重要的是,我们要停止互扔砖头的做法,想出更好的方法。

延伸阅读

~storm/teaching/reader/BentleyEtAl

原文链接:

声明:本文来自用户分享和网络收集,仅供学习与参考,测试请备份。