七大编程原语言(2022)

Hacker News Top 新闻

摘要

一篇文章探讨了七种构成大多数现代编程语言基础的编程语言原型(原语言),认为学习植根于这些原型的基础知识比选择特定语言更重要。

暂无内容
查看原文 导出为 Word 导出为 PDF
查看缓存全文

缓存时间: 2026/04/20 14:43

# madhadron - 七种编程原始语言 来源:https://madhadron.com/programming/seven_ur_languages.html ## 七种编程原始语言 我经常听到人们问该学哪门编程语言,然后列出一堆非常相似的语言(“我该学 Java、C#、C++、Python 还是 Ruby?”)。我的回答通常是:其实没关系,只要开始就行。因为背后有共通的基础原理。 所谓基础原理,指的是什么呢?如果你有一个数组或列表并要遍历它,那么在任何命令式语言中做法都一样。有直接的迭代: `` int[10] arr; for (int i = 0; i < 10; i++) { // 对 arr[i] 做点什么 } `` 也有遍历所有无序组合的方式: `` int[10] arr; for (int i = 0; i < 10; i++) { for (int j = i+1; j < 10; j++) { // 对 arr[i] 和 arr[j] 做点什么 } } `` 还有其他几种模式,但这些模式在 C、Java、Python 或 Fortran 里基本一致。拥有能流畅地用这些模式表达意图的神经通路——就像用英语句子结构表达思想一样——就是基础原理。 但并非所有语言都拥有相同的模式集合。C 或 Python 的循环模式与 Standard ML 或 Prolog 的递归模式截然不同。在 Lisp 中组织程序的方式(命名新的语言构造)与在 APL 中组织程序的方式(符号序列的片段既定义了行为,又在你的脑海中成为该行为的标签)也截然不同。 这些不同的基础原理集合构成了各种*原始语言*。学习一门同源的原始语言是轻松的转变;而学习一门源自陌生原始语言的语言则需要大量的时间、精力以及新的神经通路。 据我所知,当今软件界共有七种原始语言。我将用*模式标本*来命名它们——就像古生物学中用一个特定化石定义物种,再将其他化石与之比较来确定身份。这七种原始语言是: - ALGOL - Lisp - ML - Self - Forth - APL - Prolog ## ALGOL **特征**:程序由赋值、条件判断和循环的序列构成,并组织成函数。许多语言在此基础上增加了模块系统、定义新数据类型的方式、多态性,或者异常、协程等替代控制流结构。 **例子**:大多数常见编程语言都源自这一原始语言。ALGOL 本身包括 ALGOL 58、ALGOL 60、ALGOL W 和 ALGOL 68。主流处理器的汇编语言、Fortran、C、C++、Python、Java、C#、Ruby、Pascal、JavaScript 和 Ada 都源自这一原始语言。 **历史**:这是最古老的原始语言,可追溯到 Ada Lovelace 为巴贝奇分析机编写的程序。所有 Eckert-Mauchly 架构计算机(从 EDVAC 和最早的 Univac 开始)的机器语言和汇编语言都采用这种形式;所有早期高级语言尝试(从 Grace Hopper 的 A-0 开始,经过 Fortran 和 COBOL)也是如此。20 世纪 60 年代,学术计算机界发展了结构化编程,以使这些语言更易于管理,由此诞生了 ALGOL 60,该家族几乎所有成员都衍生于它。 随着时间的推移,该家族的成员不断吸收来自其他原始语言的特性。20 世纪 80 年代,Self 原始语言的概念被嫁接到许多这类语言中,以类的形式定义数据类型和实现多态。2010 年以来,ML 原始语言的思想也开始出现。 ## Lisp **特征**:Lisp 由括号包围的前缀表达式组成,例如: `` (+ 2 3) (defun square (x) (* x x)) (* (square 3) 3) `` 这种语法看起来很古怪,但该语言还内置了用括号包围空格分隔元素(如 `(1 2 3 4)`)来表示列表数据结构的机制。因此代码本身就是列表的形式,Lisp 系统允许你定义宏来接收列表、修改它,然后将修改后的代码传给编译器。 在编写大多数代码时,Lisp 的行为通常类似于其他原始语言(通常是 ALGOL 或 ML),但它的区别在于宏系统,允许程序员重新定义语言语义。例如 Common Lisp 中有 `loop` 语法,但它是以宏的形式定义的,而非语言内置。 **例子**:早期有许多种 Lisp,但社区在 Common Lisp 上达成了共识。与此同时,Sussman 和 Steele 探索了函数能做到多少事情,产生了 Scheme。几种特殊用途的 Lisp 也得到了使用,例如 Lush(数值计算)、AutoLISP(AutoCAD 的脚本语言)和 Emacs Lisp(实现 Emacs 编辑器行为所用的语言)。近年来,Clojure 成为 Lisp 家族的第三个主要分支。 **历史**:Lisp 比 Fortran 年轻大约一年,是当今仍在使用的第二古老的语言。它的起源是一个纯粹的数学问题:如何定义一个数学结构,使其能够求值自己的表达式?John McCarthy 在 1958 年给出了答案,随后在计算机上实现了它。这种数学背景使得早期 Lisp 在当时的机器上显得笨拙。内存和 CPU 周期的问题与数学无关,而垃圾回收等机制不得不被发明出来以使其正常工作。 在 1970 年代末到 1980 年代初,有专门从头设计来运行 Lisp 的机器。今天的大部分集成开发环境就是在那类机器上发明的。在那一时期,Lisp 本身是大多数人工智能研究的首选工具。当 1980 年代人工智能的炒作未能兑现时,该领域以及 Lisp 一起坠入了所谓的“AI 寒冬”。Lisp 至今仍顽强地存活着,尤其是在计算机性能增强、其他语言采用了当初使其实现困难的那些特性之后。 ## ML(函数式语言) **特征**:ML 语言的定义特点是函数作为一等公民,以及 Hindley-Milner 家族的类型系统,该系统足以表示不同类型的函数和带标签的联合。所有迭代通过递归完成,例如: `` sum : list of int -> int sum [] = 0 sum (x:xs) = x + sum xs `` 或者通过定义封装迭代模式、并接受另一函数来实现行为的函数: `` map : ('a -> 'a) -> list of 'a -> list of 'a map _ [] = [] map f (x:xs) = (f x) : (map f xs) `` 该家族中的一些语言(Miranda 和 Haskell)默认采用惰性求值,即直到真正需要时才求值。其他语言则在不同方向上扩展类型系统。OCaml 试图融合 Self 原始语言的概念。Agda 和 Idris 混合了值和类型(称为依赖类型系统),1ML 则混合了模块和类型。 **例子**:ML 衍生出 CaML(Cambridge ML)、Standard ML、OCaml,以及整个相关家族如 Miranda、Haskell,以及当今的依赖类型语言如 Agda 和 Idris。 **历史**:ML 是英国剑桥大学一个定理证明程序的元语言(因此得名)。该语言后来从该上下文中脱离出来,在欧洲(尤其是英国和法国)流行起来。 ## Self(面向对象语言) **特征**:程序由一组可以相互收发消息的对象组成。所有行为都通过这种方式实现。通过向现有对象发送消息来创建新对象。条件判断通过一个指向真对象或假对象的变量实现:两者都接受带两个参数的消息——一个是在真时运行的函数,一个是在假时运行的函数。真对象运行第一个函数,假对象运行第二个。调用代码不知道它发送给谁,只知道自己正在发送消息。循环也是如此。实际上,通过创建并将合适的对象插入到正确位置,你可以完全重新定义语言的语义。 这类语言通常将源文件存储在实时环境中,而非文本文件中。程序员修改实时系统并保存其新状态,而不是编译文件来生成系统。 **例子**:两个重要的例子是 Smalltalk 和 Self。有一系列语言在部分子集中实现了向对象发送消息,这种部分导入通常被称为“面向对象编程”。其中大多数以 Smalltalk 为模型。JavaScript 是个例外,它源自 Self 的无类对象系统。 这些概念还被引向了另外两个重要方向。 首先,Common Lisp 的对象系统泛化了根据接收消息的对象选择运行何种代码的想法。它将行为与对象解耦,运行时根据所有参与参数(而非仅一个)选择要运行的行为。 其次,Erlang 将执行线程在对象之间跳转以运行各种代码的概念,改为采用并行执行线程,这些线程显式地监听和发送消息。 **历史**:Smalltalk 是原始语言,开发于 1970 年代末至 1980 年代的 Xerox Parc。1980 年代有各种商业 Smalltalk 系统,IBM 使用 Smalltalk 开发其其他语言的编程工具(即 VisualAge 工具集合)。如今,Smalltalk 主要以开源 Pharo Smalltalk 的形式存续。 大量工作致力于让 Smalltalk 运行得更快更高效,最终在 Strongtalk 项目中达到顶峰。Strongtalk 在历史上很重要,因为其发现成为了 Java 的 HotSpot 即时编译器的基石。 Smalltalk 从早期语言继承了值和类型的概念,并实现了类的思想。所有对象都有一个给出其类型的类,该类用于构造该类型的对象。Self 丢弃了类的概念,仅处理对象。由于这是更纯粹的形式,我选择 Self 作为这一原始语言的模式标本。 ## Forth(栈式语言) **特征**:栈式语言是 Lisp 的反面,并且使用与惠普逆波兰符号计算器相同的文法。它们有一个数据栈。当你写入一个像数字 `42` 这样的字面量时,它被压入栈。当你写入函数名时,它不显式接受参数,而是操作栈。简单的算术看起来相当反直觉: `` 2 3 + 5 * `` 函数定义同样简洁。在大多数 Forth 变体中,`:` 定义一个新单词,本例中是 `square`。调用 `square` 时等同于先调用 `dup`(复制栈顶元素),再调用 `*`(将栈顶两个元素相乘)。 `` : square dup * ; 3 square `` Forth 允许程序员拦截解析器并用自己的代码替换它,因此文法完全可替换。常见到 Forth 程序定义小语言,例如 Fortran 子集或直接以 ASCII 方式解析描述包布局或状态机转换的图表。 **例子**:Forth 及其众多变体、PostScript、Factor、Joy(一种纯函数式语言,使用数学化的组合子代替栈)。 **历史**:Forth 最初于 1970 年编写,用于控制射电望远镜,但随后在嵌入式系统中广泛传播。由于引导一个 Forth 系统足够简单,有数十种由不同程序员为自己的目的创建的变体。 PostScript 在 1980 年代作为一种灵活描述打印文档的方式出现。它在很多方面比 Forth 更受限,但定义了与图形布局相关的原语。 ## APL(数组语言) **特征**:语言中的一切都是(n 维)数组。运算符由一个或两个符号组成,实现对这些数组的高层操作。结果极其简洁,以至于符号序列本身就成为操作的标签,而非另外命名。例如,要计算变量 `x` 中数组的平均值,可以写为: **例子**:APL、J、K。高阶数组操作已被部分导出到许多环境中,如 MATLAB、NumPy 和 R。 **历史**:APL 最初是 Kenneth Iverson 在 1960 年代创建的一种数学记号,后来他在计算机上实现。此后,它在从事密集计算的人中一直拥有小众追随者。其派生语言 K 在金融领域非常流行。 ## Prolog(逻辑语言) **特征**:程序由事实组成,可以是“事实事实”,例如 Bob 是 Ed 和 Jane 的父亲: `` father(bob, ed). father(bob, jane). `` 或者非事实事实,通过使用变量(大写开头)定义如何从其他事实推导出新事实: `` grandfather(X, Y) :- father(X, Z), father(Z, Y). `` Prolog 运行时接受这些事实和一个查询,然后搜索查询的结果。事实表明,如果选择正确的结构来定义事实,这是图灵完备的。 形成 Prolog 事实的项本身是一种原生数据类型,可以被创建并传递给运行时,就像 Lisp 的宏或 Forth 的解析器替换一样。 由于 Prolog 程序本质上是在搜索,它们的调优方式类似于数据库查询——调整搜索顺序,并尽早剪断不会产生结果的路径。 **例子**:Prolog、Mercury、Kanren。围绕这一原始语言的绝大多数编程都发生在 Prolog 本身——其社区惊人地统一。 **历史**:1970 年代,法国的逻辑学家意识到可以用一阶逻辑表达程序,并开始尝试实现。1980 年代,日本第五代计算机项目重注押在 Prolog 上,当该项目失败时,Prolog 也声名狼藉。 与此同时,数十年研究持续进行,致力于让 Prolog 运行时足够智能以在大多数情况下高效工作,以及增加新能力(如数值约束,产生约束逻辑编程)。 Prolog 往往出现在一些特定领域。Java 的类型检查多年来用 Prolog 实现,Facebook 最初的源代码搜索工具也是如此。 ## 如何利用这些知识 对于大多数程序员来说,其中一些甚至全部原始语言可能看起来非常另类。花些时间接触每一种原始语言是值得的,因为它们会促使你生长新的神经通路,并带来新的可能性。很多时候,从 ALGOL 视角看完全不同的两件事,通过另一个视角看去就变成了微不足道的比较。 **首先**,每个程序员都需要熟练掌握一门 ALGOL 家族的语言。 **其次**,学习一门 Prolog 家族的语言:SQL。这是因为在 ALGOL 家族之后,SQL 将是你职业生涯中回报最高的语言。我将人们学习 SQL 时最常见的障碍整理成了一份免费课程(https://madhadron.com/imperative_to_relational.html)。 **然后**,一旦掌握了这两者,就值得拓展视野。每年学习一门源自陌生原始语言的新语言会带来丰厚的回报。在以上每个家族中,我今天建议的语言分别是:

相似文章

以理论构建的视角阅读编程

Hacker News Top

本文推荐 Peter Naur 的著作《编程即理论构建》,主张编程的本质在于构建和传达对软件的心理模型,而不仅仅是编写代码。

递归模式的隐秘历史

Lobsters Hottest

一场演讲,追溯从goto面条代码到结构化循环,再到递归模式的演化历程,展示控制流抽象如何映射数据结构,以及为何大多数语言仍把最好的组合子藏起来。

对 APL 等数组语言的有原则性重新思考

Lobsters Hottest

本文提出了一种有原则性的方法来重新思考 APL 等数组语言,通过将变量建模为输入维度的函数,旨在相较于传统方法提高可读性和错误检查能力。