点击登录
    便宜出个双拼域名,ruocuo.com,有意的联系站长。

这些被遗忘的编程语言,还在诉说他们的故事

知乎日报 学习热 66次浏览 0个评论 扫描二维码

因为这些被遗忘的语言,还在诉说他们的故事啊。

去自然化

1978 年,为了记录下编程语言的发展,展开了会议。

这某种意义上,算是 PL 的‘华山论剑’-

天下各路 PL 中极小数强者,聚集(语言不会走路,是这些语言的设计师&实现者聚集)。

13 个入选的语言中,5 个有图灵奖得主参与!(APL, Algol, Fortran, Lisp, Simula)

这等豪华阵容,只怕再也凑不出。

当然,没有什么比武。不过,之后又举办了两次 HOPL,总计三次,真是个美妙的巧合啊。

在这个大会上,Opening 是 Grace Hopper,Cobol 的主刀。

我读到这的时候,也很不解。

Cobol 何德何能,为何能占着 Opening,这位置上面的 5 个‘图灵奖语言’那个不更有资格?

她说:“我被你们震惊到了。你们都是权威,然而我这辈子花了 20 年去跟权威作斗争!PL 早期中我们最常听到的话是‘编程计算机的唯一方法是 8 进制。’(省略)在那时,权威跟我们说,用计算机编程是不可能的,计算机唯一能做的只有算术。”

一个编程语言,条件判断靠 if else,自指用递归,组成更大的数据类型用 struct。。。

这几个构造如此天经地义,导致看上去没有任何其他 alternative:还能怎么弄。

然而,连‘编程语言’在当时很多人眼中都是不可能,这些构造又怎么可能‘自然’呢?

if else,是 1960 左右,John Mccarthy 发明,并且加入 Algol 60。

在此以前,Fortran 只有 if 后面跟着一个 int 表达式,然后跟着三个整数 – 跳转的行号!

(没错,goto 在当时是跳转到行号的)

当然,Fortran 也一样被‘权威’看不起,认为‘一切高级编程语言都很慢,不够用’。

听上去像不像 C 语言程序员嘲笑其他高级语言慢?

这就是学历史的另一个好处:知道什么论点会被历史的车轮碾压。

PL 的递归,是同时由 John Mccarthy 发明的。值得一提的是,这特性差点没进 Algol 60。

至于 struct,一开始只有 Cobol 才有,到了近 8 年后,到了 Algol 68,才传播到各个语言。

函数式程序员别得意,John 自己也搞不懂啥是 Lambda Calculus,到了 1964 Peter Landin 才指出 Lambda Calculus 可以用来编程。

而事实上,if else, recursion, struct, lambda,全部都有人改过,并且投入使用。

把 if else 改成 if … else if … else if … (没有最终 else),然后不规定同时满足多个条件时,进入那个分支(non determinism),就有 Dijkstra 的 Guard Command Language。这个语言可以由于是不确定的,可以用来组合多线程的 blocking channel(见 Concepts of Programming Languages)。有趣的是,Dijkstra 发明的时候,没想这么多,只是因为单纯的‘if else 不对称,好丑’而去改。

递归则可以完全去掉,改由 recursion scheme(list 的 foldr 或者相近的,但是更复杂的,构造 / 使用数据结构的高阶函数)。用 recursion scheme 的人,有时候会说‘无限制的递归就是新的 goto’。这是因为对于用了递归的程序,要证明这程序的属性,只能用归纳法,而如果用 recursion scheme,就能用事先(通过归纳法)证明的引理去辅助证明。打个比方,如果你用 list 上的 map,而不是手动递归,你写程序的时候就能引用定理 map f . map g = map (f . g)。(注:map 不是 recursion scheme)

至于 struct,在 Algol 68 中,就提供了 Algebraic Data Type。除了‘类型 T 能通过给人类型 X 跟类型 Y 的值来构造’以外,还有‘类型 T 能通过给入类型 X或类型 Y 的值来构造’。这跟 union 有点像,但是会记下是‘或的那边’,换句话说,是 disjoint union。这特性是用来描述 AST(Abstract Syntax Tree)的首选,所以基本上所有钟爱元编程的静态类型语言(如 ML,Haskell)都有。

而 lambda calculus 中的 arrow type,在 linear logic(一种限制所有资源都必须使用刚好一次的逻辑系统)中,则可以拆分成两个更细的 construct:a -> b = !a -o b。其中,!x 代表可以任意复制的 x,x -o y 代表给入一个 x,消耗之,输出一个 y。!a -o b 则表明,给入可以任意复制的 a,消耗之,输出一个 b。由于 a 可以任意复制,所以消耗了不要紧,换句话说这就是给入 a,输出 b。(见 A Taste Of Linear Logic)同时,在 OO 界,Luca 由于 Lambda Calculus 的限制,难以用之模拟 class,object,subtyping,于是自己发明了另一套 calculus – Object Calculus(见 A Theory of Object)。

还有一个怪胎,APL- 这语言里面抛弃了这些概念,一切都通过对数组的变换来完成。(其实还是有的,不过不提倡使用)

不学历史,很容易认为这些东西生来如此,没什么好改的 – 尽管计算机的发明还不到 100 年!

同时,看着这些先驱开天辟地,创造一切,有莫名的史诗感,说不出的好受。

提取精华

等你学了点历史,对编程语言的可塑性有更深刻理解,并且开始假想基本构造的更多形式的时候,你就到达破而后立的‘破’了。当然,破而后立,你还需要会写 Parser/Compiler/Interpreter/VM,会弄类型系统,宏,等等。。。

然而,这还不够。

一个语言,首先是一种编程方法,一套认为人类如何编程最高效的理论,然后才是围绕着这个理论而生的 feature。世界上绝大部分(不是完全没人用)的语言,如 Algol, Cobol, Fortran, APL, C, C++, Python, Perl, Scheme, Haskell, Smalltalk, CPL。。。都有这东西。

在 C++ 中,这叫 Design Philosophy, 在 Python 中,称作是 pythonic,Smalltalk 中,是 Design Principle。。。我们统称之为 Principle。没有 Principle,造出的语言,只能是旧有语言的无机混合,看上去很好,然而没有新意。

Principle 是一个语言的内核。有了 Principle,可以用之更改过往的语言 construct,得出一个全新的语言。在 The Essence of Algol 中,John Reynold 就是从一个他认为是 Algol 中很重要的部分,慢慢推出各种 construct,得出一个小而全的 Algol。

要注意,Principle 并不是为了推出 Feature。相反,是 Feature 为 Principle 服务。换句话说,如果一个语言中,有跟 Principle 不匹配的 Feature,要做减法,砍掉 Feature。

比如说,Structured Programming 认为,由于测试不可能保证正确性,我们需要用 Hoare Logic 推出程序的正确性。但是,与其正推,我们可以一步步的从终止条件倒推,到最后,从证明中取出程序(又或者说,证明就是程序)。这叫做 Stepwise refinement,而 Structured Programming 舍弃 goto,不是因为‘Structured Programming = Programming without goto’,而是 Stepwise Refinement 恰巧不支持 Goto 而已。盲目的去掉 Goto,是治标不治本。

Functional Programming 则认为,大的程序最好由小的,相互独立的程序(两个程序的用途都可以跟另一个分开)组合得出。如果程序 A 会影响程序 B,就不是相互独立的,所以 FP 不提倡 Effect。在 FP 中,独立组合性是治本,移除&控制 Effect 是治标。

除了 Paradigm 的 Principle,每个语言自己也有各自的 Principle-Smalltalk 的是 Design Principles Behind Smalltalk,APL 的是 Notation as a Tool of Thought,Algol 的是 The Essence of Algol。学习 PL 史,是发现 Principle,并观察 Principle 如何慢慢构造一个语言。

正本清源

除了发现 Principle,并观察 Principle 的发展,影响,可以反着,研究 Principle 如何诞生。

这样做,可以明白一个 Principle 的本质,又或者可以自己照猫画虎,搞出自己的 Principle。

往往,这样做会走出 PL,甚至 CS 的边界。

Logo 对 smalltalk 有很大的影响(如 Alan Kay 对 Personal Computing 的理解就被 Logo 影响了,见 Early History of Smalltalk),而 Logo 的 3 Principle(Principle of Power,即学即用,Principle of Continuity,学的东西跟以往的东西有紧密连接,Principle of Culture,社区中其他人日常生活会接触到学的东西),则来自 Jean Piaget 的认知发展理论。

同时,这些 Principle 的来源,说不定自身就很有启发性,找到了,就是攒到了。

比如说,说远一些,Robert Harper 发现了,就算是有 bug 的程序,也可以用 formal verification 的方式看待之。只不过,这时候证明就无法完成。然后,通过审视证明为何无法完成,就知道 bug 在那,而无需要写测试瞎猜。这叫 Proof Directed Debugging。

而这方法,来自于数学 / 哲学的著作,Proofs and Refutations。这本书讲了数学证明的发展史,并且论述,数学证明并不是通过 Formal Proof 得出的,而是通过 trial and error。在此以前,我还以为数学的发展是通过 Formal Proof&Informal Hole 的,现在才明白除了写证明,还有下定义,找猜想,generalize,debug 证明等等,也托这的福,找到了 Abductive reasoning。而这,仅仅因为我看 Proof Directed Debugging 的时候查查这的历史。

爽!

一方面,查历史就像探宝一样,往往会在意想不到的地方跳出惊人的事件:比如说,易语言的近似物在早近 30 年前,就已经出现了 – 由于 Algol 不限字符集,在 1972 就有一个叫 Chinese Algol 的方言。当然,还有更重要的,比如说设计 CPL,C 的前前前身的人,据说对 ISWIM 有不小的影响。

另一方面,丘处机为什么要路过牛家村?

历史学得越多,就会越来越发现当下的巧合,然后去幻想平行世界的展开。其中,最可惜的是,1948 年就有一个跟得上 60 年代的语言 – Plankalkül。这是最早的,有 if/struct/loop 等的语言,足足超前了 Algol/Lisp/Cobol/Fortran 10 年!如果这语言更早被更多人知道,又或者 Algol 60 没有引入递归,又或者 John Mccarthy, Alan Kay, Dijkstra, Seymour Papert, John Backus 等人改行。。。不知道那样,我们现在会在用什么语言呢。

客官,这篇文章有意思吗?

 


学习热 , 版权所有丨如未注明 , 均为原创丨转载请注明这些被遗忘的编程语言,还在诉说他们的故事
喜欢 (0)
支付宝[[email protected]]
分享 (0)
关于作者:
90后,宁飘