Lisp 永远成不了编程主流语言 vs Lisp 神话之路

Lisp 的争议

由于 Lisp 语言的 “过于灵活而神秘存在” 的特性使得 Lisp 成了世界上最受争议的编程语言,实际上独树一帜的 Lisp 也在(针对不同的产品,总有热衷「语言比较」的人们引发语言优势性的争论)类的问题得到庇护,因为 Lisp 语言本身不是针对开发项目而诞生的语言,这种性质完美的避开了针对项目类型而友好的语言之间的比较话题。尽管如此,还有很多人用「Lisp 永远成不了编程主流语言」来反驳极少 Hacker 所说的「Lisp 是 Hacker 们最好的神器」。
虽然 「Lisp 永远成为不了主流的编程语言」这个问题本身就是伪命题,因为 Lisp 从来没打算成为主流的编程语言,Lisp 与众不同的部分原因是,它被设计成能够自己进化。你能用 Lisp 定义新的 Lisp 操作符。当新的抽象概念风行时(如面向对象程序设计),我们总是发现这些新概念在 Lisp 是最容易来实现的。Lisp 就像生物的 DNA 一样,虽然 Lisp 没打算成为主流语言,但这样的语言永远不会过时。

接下来我们还是引用两篇文章进行说明:

  • 「Lisp 永远成不了编程主流语言」
  • 「为什么 Lisp 没有流行起来」

Lisp 永远成不了编程主流语言

Lisp 语言是第二古老的高级编程语言。许多的黑客和开发者对 Lisp 推崇备至,Paul Graham 甚至说 “编程语言现在的发展,不过刚刚赶上 1958 年 Lisp 语言的水平”。

   然而这样先进的语言在现在使用的编程语言从来没有排到前20,听说它的人不少,用的人却非常少。

   许多人对 Lisp 语言的第一印象就是一层层的括号,很老的关于苏联黑客偷到 Lisp 源码的最后一页全是括号的笑话就不用再说了。

造成 Lisp 程序如此多括号的原因就是 「S表达式」。所谓 S表达式,是指一种以人类可读的文本形式表达半结构化数据的约定,是点对表示法的形式定义。

S表达式 是 Lisp 语言的鲜明特点,使数据和代码形式统一,让使用者有能力对程序和数据进行统一处理。

   Lisp 语言使用这统一的 S表达式,让 A+B 变成了 (+ A B),数据是统一了,却让人别扭了,尤其在使用更复杂的四则混合运算时更让人难以接受。然而那些 Lisp 拥护者对这些不能接受 S表达式 的人总是持批评鄙视的态度。

   Lisp 未能成为主流的根本原因是这一语言是反人性的,它的先进是对于机器的先进,就像二进制对于计算机来说是先进的一样。

   人是生物,对事物的需求都有着多样性的需求,人类的所有语言对漂亮的形容词从来不止一个,对颜色的要求从来就不止黑白亮色,所以在数字上选择了十进制而不选择二进制,这是最基本的人性。Lisp 使用 S表达式 抹平了一切多样性,禁止人类数千年来不约而同选择的的 A+B 这样的中缀表达式规则,违反了人性,所以受到了广大开发者的不接受。

   简单说,Lisp 语言违反了人类人性中对事物多样性的需求而不能成为编程语言中的主流。

为什么 Lisp 没有流行起来

很久以前,这种语言站在计算机科学研究的前沿,特别是人工智能的研究方面。现在,它很少被用到,这一切并不是因为古老,类似古老的语言却被广泛应用。

其他类似的古老的语言有 FORTRANCOBOLLISPBASIC、 和 ALGOL 家族,这些语言的唯一不同之处在于,他们为谁设计。FORTRAN是为科学家和工程师设计的,他们在计算机上编程的目的是是为了解决问题。

COBOL 是为了商业设计的,最好的体现在于让商人们可以利用电脑时代。LISP是了计算机科学研究设计的,最突出的体现在计算机基本原理研究。BASIC是为初学者设计的。

最后,ALGOL 语言是有计算机程序员修改,演变成其他流行的语言,如C,Pascal 和 Java 的一个庞大的家族。上面提到的某些语言已经不像当初那么流行了。我们在这里可以把它们称作 “失败”。

问题是它们为什么失败?第一站出来的是 COBOL,很不幸,它以面向商业人员的很好的可读性就是它的失败点。商业人员发现,他们可以雇佣程序员去管理他们的系统。程序员自然会偏向于为他们设计的语言,而不是他们的老板。

所以随着时间推移,越来越多的商业功能都使用例如 VB,C,C++ 和 JAVA 实现了。现在,只有很少一部分软件仍通过 COBOL 语言编写。BASIC 却有不同的命运。他是为入门人员设计的。那些在微机上学习编程,他们会使用内置的 BASIC 语言作为起点。

随着时间推移,微机被运行微软操作系统的个人电脑,或者 MacOS 的苹果电脑所代替。这种语言逐渐被 VB 所取代。虽然他是面向初级程序员,它有一段时间代替了 COBOL。为什么要耗费这么多的资源在昂贵的编译器上,而便宜的解释器在我们的电脑上已经存在?

最近,微软以迁移到 .NET 框架上,让 VB 跟在后面。它的替代者, C# 就是 ALGOL 家族中的一员,跟 Java 相近。这些年 FORTRAN 的使用起起伏伏。在某一阶段,差不多所有科学方面的代码是用它来写的。它的优点是这门语言中没有指针,并且不允许存在递归。

这意味着所有数据的引用位置都可以在编译时确定。FORTRAN 编译器 利用这些额外的信息使程序运行格外地迅速。不幸的是,随着时间的推移,固定大小的数组这种数据结构变得过时了。现在,科学要处理任意形状的风格,甚至表述更为复杂的真实世界。

这需要在语言中额外地加入指针。这些情况发生的时间段里,FORTRAN 逐渐走向没落。现在,它被转移到高性能计算工作,其中新的并行矩阵和矢量运算最近添加到这门语言中,仍然使它拥有性能优势。ALGOL 语言家族取得了成功。

其原因是,这些语言是由程序员为程序员写的。随着时间的推移,这些与系统和应用相关的语言成为了现在最常用的语言。它的优点是越多地程序员使用,这门语言就能得到更多地改进,并且越来越多地程序是用它们来写就的。这提供了一个良性循环,更多的程序员们又被聘请在己编写的程序上工作。

这是一个网络效应的例子。一个系统的 “价值” 是它的用户数目的平方,在于以此速率增长的用户之间的交互作用。那么为什么Lisp语言家族会站在失败者一边呢?有些人认为是语法的错。Lisp 因为它的括号而臭名昭著。我并不认为是这个理由。许多用户说良好的格式可以让他们跟上这些括号。

同时,Lisp 语言被发明不久后,有一个叫 “super-bracket” 的语法可以让人快速表示出任意数量的回括号 “ ) ” 。这个特性在今天已经很少有人使用了。最后,优秀的编辑器解决了大多数的语法问题。另一些人经常抱怨 Lisp 是一门函数式语言。这是失败的理由吗?自然,跟早期的语言相比,只有 Lisp 算是函数式的。但事实上,我认为没有这么简单。Lisp 也有命令式语言的特性,ALGOL 系列语言也可以被当作一门纯正的函数式语言来用。

如果有人想选择一种特定的编程范式来写代码,一些特定的语言可以让这个选择更容易的实现。然而,现代语言已经足够灵活,它们能支持多种编程范式,近乎完全命令式的Lisp没有理由不存在。或许lisp的问题在于他使用了垃圾回收?

在那个时候,只有 Lisp 作为计算机语言采用了这个特性。诚然,垃圾回收会占用大量的计算资源,而早期计算机在该方面的不足足以组织 Lisp 大展拳脚了。但是,我认为这仍然不是主要的原因。

Lisp 是用来写那些复杂度相当高的程序的,而这些程序在事实上都必须带有一个垃圾回收模块,如果你用其他的语言来写…… 大概很难比 Lisp 实现的要好吧?众所周知的事实是,任何一个如此复杂的程序,如果用其他语言写的话都不可避免的戴上一个比 Lisp 垃圾回收臃肿不少的功能模块…… Lisp 的失败,恰恰是因为他太成功,这让他的目标变得模糊。Lisp相对与早期的语言实在是非常灵活,灵活到足以改变自身形式以适应需求。对于其他的语言来说,如果想要完成一个庞大的任务,就需要把这个任务打碎成一小块一小块的然后完成。

如果是一个更大的呢?甚至连编译都需要分步完成了。但是 Lisp 不是这样的,由于他强大的能力,程序员可以将 Lisp 改造成特定领域的专门工具——顺手的工具将顺手的解决问题——任务轻松完成了。

由于语言的正交性(译者注:这里可能应该理解为 “自洽” ),我们改造过的 Lisp 仍然可以使用原有的编译器,解释器运行。那么建立特定领域的语言来作为一个问题的解决方案,它会出现什么问题呢?

结果是它非常高效。然而,这种做法会使语言分化。这导致许多子语言都略有不同。这是 Lisp 代码对其他人而言可读性差的真正原因。在其他语言中,相对来说比较简单就能臆测出一段给定代码的作用。

有着超强的表达力的 Lisp,由于一个给定的符号 (symbol) 可能是一个变量,函数或操作,需要阅读大量代码才能找出它。Lisp 失败的原因是因为它的碎片化,并且它的碎片化是因为其语言天性与特定领域方案的风格造成的。

而网络效应则恰恰相反。越来越少的程序员使用相同的方言,因此它相对与 ALGOL 语言家族的总价值下降。如果有人现在设计一种语言,该如何避免这种问题呢?如果语言的表达性是我们的目标,那么它必须以某种方式加以调整。

这门语言必须要有特意的限制,来保证所编写代码的可读性。Python 是一门成功的语言,它已经做到了这些,其中某些限制是硬编码的,而另一些则是以约定成俗的方式存在。不幸的是,这么久过去了并且发明了这么多 Lisp 的变种语言,在其之上建立的其它新语言大概并不是所要的答案。

根本不会有足够多的用户使它与众不同。也许解决的办法是,慢慢加入类似 Lisp 的语言功能到 ALGOL 语言家族中。幸运的是,这似乎是正在发生的事。新的语言(C#DPython 等)趋向于拥有垃圾回收机制。他们也往往比旧的语言更具正交性。

Lisp 语法反人性中的隐藏宝藏

如果你刚开始学习的时候,主要是忍受着它那前缀表达式和大量的括号,去学习它的函数式编程,这时候没觉得 Lisp 有多厉害,等到学到了 宏(macro)这个主题的时候,就被 Lisp 的变态的能力真正地震撼了:

这不是一门简单的编程语言,它是一门创造其他语言的语言。

Lisp 在制造别的语言(DSL)时是如此的成功,以至于它最终走向了 “失败”。

很多语言解决问题的思路是分而治之:把一个大任务拆分成一个个小任务,再把小任务拆分成更小的任务,然后去编码实现。

Lisp 则有着截然不同的思路,由于其强大的能力,Lisp 程序员倾向于改造 Lisp,把这门语言改造成一个问题领域相关的语言,即 DSL ,然后用这个 DSL 来轻松编程,去解决问题。

当然这个改造的过程是个渐进式的:

“在编程的时候你可能会想 'Lisp 要是有这样或者那样的操作符就好了。' 那你就可以直接去实现它。之后,你会意识到使用新的操作符也可以简化程序中另一部分的设计,如此种种。语言和程序一同演进。就像交战两国的边界一样,语言和程序的界限不断地移动,直到最终沿着山脉和河流确定下来,这也就是你要解决的问题本身的自然边界。最后你的程序看起来就好像语言就是为解决它而设计的。并且当语言和程序彼此都配合得非常完美时,你得到的将是清晰、简短和高效的代码。”    
--- Paul Graham 《On Lisp》。

这种使用DSL去解决问题的方法有什么问题呢?

  • 碎片化!  会出现很多“小语言”,这些语言之间有细微的不同,这就是为什么你的 Lisp 代码对别人来说读起来很吃力的原因。

  • 而其他语言则不存在这个问题,相对容易去理解代码的含义。Lisp, 由于其变态的表达能力, 一个符号可能是个变量,函数,操作符。你需要花费大量时间去阅读代码才能搞清楚它到底是什么含义,这就太悲催了。

  • Lisp 的 “失败” 的一大原因就是它的碎片化,而碎片化又源于语言本身的特性和它那用 DSL 解决问题的风格。

我在说 “失败” 的时候,一直用引号, Lisp 真的失败了吗?No!Lisp的思想已经进入到了现在主流的语言中,无论是 Python,JavaScript,甚至 Java 都具备函数式编程的能力,还有像 Scala 这样既能OOP,又能 FP 的语言。
但是,Lisp 那强大的宏,那运行时改变自身的能力并没有被其他语言接受,Ruby 比较接近,但是差得还很远。可能大家害怕这个双刃剑了吧!

本作品采用《CC 协议》,转载必须注明作者和本文链接
不要试图用百米冲刺的方法完成马拉松比赛。
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!