Paul Graham Essays

返回

Lisp 之所以与众不同的原因

发布于 2007-02-17

原文:https://www.paulgraham.com/diff.html

2001 年 12 月(修订于 2002 年 5 月)

(本文是对LL1邮件列表上一些问题的回应而产生的。现已纳入Revenge of the Nerds。)

当麦卡锡在 20 世纪 50 年代末设计 Lisp 时,它是与现有语言截然不同的,其中最重要的是Fortran

Lisp 包含了九个新的概念:

1. 条件语句。 条件语句是一个 if-then-else 结构。我们现在认为这是理所当然的。这些是由麦卡锡在开发 Lisp 的过程中 [发明的](http://www- formal.stanford.edu/jmc/history/lisp/node2.html)。 (当时的 Fortran 只有一个条件转移指令,紧密基于底层硬件的分支指令。)麦卡锡是 Algol 委员会的成员,他把条件语句引入了 Algol,从而传播到大多数其他语言。

2. 函数类型。 在 Lisp 中,函数是一类第一类对象 — 它们是一种数据类型,就像整数、字符串等一样,并且有一个文字表示,可以存储在变量中,可以作为参数传递,等等。

3. 递归。 递归在 Lisp 之前当然作为一个数学概念存在,但 Lisp 是第一种支持它的编程语言。(这在使函数成为第一类对象时可以说是隐含的。)

4. 变量的新概念。 在 Lisp 中,所有变量实际上都是指针。值才有类型,而不是变量,给变量赋值或绑定意味着复制指针,而不是它们指向的内容。

5. 垃圾回收。

6. 由表达式组成的程序。 Lisp 程序是表达式树,每个表达式返回一个值。(在某些 Lisp 中,表达式可以返回多个值。)这与 Fortran 和大多数后续语言形成对比,后者区分表达式和语句。

Fortran 中有这种区别是很自然的,因为(在输入格式是打孔卡的语言中并不奇怪)该语言是面向行的。你不能嵌套语句。因此,虽然数学运算需要表达式,但没有必要让其他东西返回一个值,因为也没有任何东西在等待它。

随着分块结构语言的出现,这种限制消失了,但那时已经为时已晚。表达式和语句之间的区别已经根深蒂固。它从 Fortran 传播到 Algol,然后传播到它们的后代。

当一种语言完全由表达式构成时,你可以随意组合表达式。你可以使用(使用Arc语法)

(如果 foo (= x 1) (= x 2))

或者

(= x(如果 foo 1 2))

7. 符号类型。 符号与字符串不同之处在于你可以通过比较指针来测试相等性。

8. 用符号树表示代码的符号。

9. 整个语言始终可用。 读取时间、编译时间和运行时间之间没有真正的区别。你可以在读取时编译或运行代码,在编译时读取或运行代码,在运行时读取或编译代码。

在读取时运行代码让用户重新编写 Lisp 的语法;在编译时运行代码是宏的基础;在运行时编译是 Lisp 作为像 Emacs 这样的程序中的扩展语言的基础;在运行时读取使程序能够使用 s 表达式进行通信,这个想法最近被重新发现为 XML。

当 Lisp 首次被发明时,所有这些想法都远离了普通的编程实践,这主要是由 20 世纪 50 年代的可用硬件所决定的。

随着时间的推移,体现在一系列流行语言中的默认语言逐渐朝向 Lisp 发展。1-5 现在已经广泛传播。6 开始出现在主流中。Python 有一种形式的 7,尽管似乎没有任何语法。8(与 9 一起)是使 Lisp 宏成为可能的基础,到目前为止仍然是 Lisp 独有的,也许是因为(a)它需要那些括号,或者其他同样糟糕的东西,和(b)如果你添加了那最后一点权力,你不再能声称发明了一种新语言,而只能说设计了一种新的 Lisp 方言;-)

尽管对现代程序员有用,但用其他语言采用的随机权宜之计的变化来描述 Lisp 是奇怪的。这可能不是麦卡锡当初考虑的。Lisp 并不是为了纠正 Fortran 的错误而设计的;它更像是试图公理化计算的副产品。

日文翻译

最后编辑于 2024-04-15