QIAOPANG.COM · 陈天(TYR CHEN)2013–2026 精选技术与随笔文集 · 共 260 篇按时间顺序浏览(2013 → 2026)↗
程序人生 · 陈天文集QiaoPang · Systems, Craft & Agentic Era
时间轴 ↗

编程语言的慢演进:从 1960 年代到 AI 时代的语言进化悖论

编程语言的慢演进:从 1960 年代到 AI 时代的语言进化悖论

横看成岭侧成峰,远近高低各不同。不识庐山真面目,只缘身在此山中。 —— 苏轼《题西林壁》

身处编程语言的演进之中,我们往往被语言表面的新特性迷惑,而看不清历史的脉络。真正的洞察需要跳出当下的视角,从历史的维度审视语言的本质。所谓创新,多是对过去的重新发现;所谓进步,常是在既定轨道上的缓慢前行。

有个挺有意思的现象:技术圈天天喊着 AI 革命、量子计算、元宇宙,但你看看大家每天用的编程语言,前十名基本都是上个世纪的「老古董」。这是为啥?

最近看了 Kevlin Henney 在 GOTO 2024 的演讲「Programming Languages: Past, Present, and Future」(https://www.youtube.com/watch?v=0y7IFUYUTgg),他用数据和历史告诉我们答案。更扎心的是,他说 AI 时代不但不会让编程语言更新换代,反而会让老语言更加根深蒂固。

先说个简单但很多人忽略的事实:编程语言不是什么细枝末节,它是一切的根基。

编程语言:软件世界的「地心引力」

Kevlin 打了个很妙的比方:NASA 那个 160 米高的火箭装配大楼,看起来很宏伟,但它的形状完全取决于两个看不见的东西 —— 材料和重力。换了任何一个,整栋楼就得重新设计。

编程语言就是软件世界的「重力」。它无处不在,决定着你怎么思考问题、怎么设计系统、甚至团队怎么协作。不信?让你们团队明天换个语言试试 —— 这可不是换个工具那么简单,整个技术栈、思维习惯、开发流程全得推倒重来。

Kevlin 说得好:「如果编程语言真的无关紧要,你咋不明天就换一个?」

历史的重量:1960 年代的语言革命

让我们回到 1960 年代,那个看似遥远却影响深远的年代。

编程语言的慢演进:从 1960 年代到 AI 时代的语言进化悖论 架构图

ALGOL 68:被遗忘的巨人

你可能压根没听说过 ALGOL 68,更别提用它写过代码了。但有意思的是,你每天敲的那些关键词 —— int、char、void、struct、union —— 全都是从这门语言来的。在它之前,编程语言都老老实实用完整的单词:integer、character、boolean。

ALGOL 68 可不光是把关键词变短了这么简单,它还搞出了表达式导向的编程风格。没有 return 语句,所有东西都是表达式。这个设计思路后来被函数式编程语言玩得飞起。

if-else 的发明:一个看似简单的创新

听起来有点扯,但 if-else 这玩意儿还真是需要被「发明」出来的。英语里大家都说「if something, otherwise」,谁会说「if something, else」?早期搞编程语言的大佬们为这事儿可没少纠结:

  • Grace Hopper 在 FLOW-MATIC 里用的是 OTHERWISE
  • John McCarthy 早期设计 Lisp 时也觉得 otherwise 比较顺口
  • ALGOL 58 的提案里还有 or if 和 if either 这些奇葩选项

一直到 1960 年,ALGOL 60 委员会才拍板用 else。Klaus Samelson 这哥们儿是关键人物,他被 McCarthy 的想法打动了,力推这个简洁的关键词。

协程:60 年前的「新」概念

现在的程序员一提到 async/await、goroutines、协程这些东西就激动得不行,但你知道吗?协程(coroutines)这个概念是 1958 年就有的。没错,1958 年,那时候很多读者的父辈们可能都还没出生呢。

Melvin Conway(对,就是那个搞出 Conway’s Law 的大神)在 1958 年就琢磨出了协程这个概念。Donald Knuth 在 60 年代初期还专门深入研究了一番:「主程序和子程序之间是老大和小弟的关系,但协程之间完全是平等的哥们儿。」

// 现代 Rust 中的协程风格
async fn fibonacci_generator() -> impl Stream<Item = u64> {
    let (mut a, mut b) = (0, 1);
    stream! {
        loop {
            yield a;  // 1970年代的 yield 概念
            (a, b) = (b, a + b);  // 1963年的多重赋值
        }
    }
}

Barbara Liskov 在 70 年代搞出了 CLU 语言,里面的迭代器直接就用了 yield 关键词。现在 Python、JavaScript、C# 里的生成器和迭代器,说白了就是在重新发明半个世纪前的轮子。

令人震惊的稳定性:语言也有冻龄现象

来看看 2024 年 9 月的编程语言排名,这数据挺有意思的:

编程语言的慢演进:从 1960 年代到 AI 时代的语言进化悖论 架构图

把 TIOBE、RedMonk、IEEE Spectrum 三大排名的 Top 20 综合起来看:

  • 80% 的语言都是 2000 年之前造出来的
  • Top 5 直接霸占了 55% 的市场份额
  • Top 10 更是占了 67% 以上

这就是典型的幂律分布(Power Law),社会结构里到处都是这种模式。更有意思的是按年代来看:

编程语言的慢演进:从 1960 年代到 AI 时代的语言进化悖论 架构图

那个「千禧一代」的大饼就钉在那儿了,成了编程语言历史上永远的一个山头。这意味着啥?大部分刚毕业的小年轻,用的编程语言比他们岁数都大。

社会性超越技术性:语言成功的真正密码

重新想想这个问题:为啥有些语言能一直火下去?答案可能会让技术原教旨主义者很失望:编程语言能不能成功,主要看社会因素,技术牛不牛逼反而是次要的。

Java:「无趣」即是特性

有次聊天时,有人说「Java 作为一种语言挺有趣的」,Kevlin 直接怼回去:「no no no,它很无趣」。但有意思的是,这恰恰是 Java 能成功的原因。

Java 从 1995 年出生那天起就不是一门「有趣」的语言。没有什么革命性的概念,语法也谈不上优雅,Lambda 表达式都拖到 2014 年才加进去(比 C++ 还晚)。但就是这种「无趣」—— 稳定、可预测、向后兼容 —— 让企业最喜欢用它。

语言进化的收敛效应

看看最近几年主流语言的更新,你会发现一个有意思的事儿:大家都在往一个方向跑。几乎所有主流语言都在加这些东西:

  • Lambda 表达式和闭包
  • 模式匹配
  • 类型推断
  • 异步编程支持
  • 函数式编程特性
// Rust 的模式匹配和类型推断
let result = match value {
    Some(x) if x > 0 => x * 2,
    Some(x) => x,
    None => 0,
};

// 函数式风格的集合操作
let evens: Vec<i32> = (0..100)
    .filter(|x| x % 2 == 0)
    .collect();

John Backus 1977 年就看出来了:「每个新语言都会把前辈的特性全抄过来,然后再加点新花样。」只不过现在不是造新语言了,而是往老语言里不停地塞新功能。

函数式编程的悖论:永远的明天

1977 年,John Backus 拿图灵奖的时候问了一句:「编程能不能摆脱冯诺依曼那一套?」他说函数式编程就是答案。

47 年过去了,咱们看看函数式编程语言在排行榜上的表现:

三大排名的 Top 20 里,纯函数式编程语言有几个?0 个

没错,一个都没有。Haskell 没进去,Clojure 没进去,F# 也没进去,甚至老祖宗 Lisp(偶尔能混进前 30)都比 Clojure 排名高。

但这不代表函数式编程失败了。恰恰相反,它的思想已经渗透到几乎所有主流语言里了。这就跟太极拳似的 —— 虽然没几个人专门练纯正的太极拳,但太极的理念(以柔克刚、借力打力、阴阳平衡)被各种现代武术和健身方法都借鉴了。这些语言不是函数式的,它们只是偷学了点函数式的「内功」。

Excel:意外的函数式编程王者

Simon Peyton Jones(Haskell 的大佬)说过一句让人扎心的话:「Excel 是世界上最流行的函数式编程语言。」

很多程序员听了都不爽,因为这意味着财务部那帮人可能比他们更早开始「函数式编程」了。想想也对,Excel 的每个单元格都是纯函数,整个表格就是一个巨大的数据流图。没有副作用,没有可变状态,妥妥的声明式编程。

更搞笑的是,2020 年疫情期间,微软的工程师闲得没事干,决定给 Excel 加个 Lambda 函数支持。这就像给一辆已经跑得挺好的车加了个火箭推进器,几乎没人会用,还不如去修修 Excel 那些真正让人头疼的老毛病。

AI 时代:进化的刹车而非油门

这就引出了 Kevlin 演讲里最精辟的观点:AI 和大语言模型火了之后,不但不会加速(给人类使用的)编程语言的进化,反而会变成一股强大的保守势力。

LLM 的统计偏见

编程语言的慢演进:从 1960 年代到 AI 时代的语言进化悖论 架构图

大语言模型天生就是保守派,原因很简单:

  1. 训练数据偏老:老代码比新代码多得多,旧版本的例子比新版本多得多
  2. 流行的更准:语言越流行,数据越多,AI 给的建议就越靠谱
  3. 循环加强:AI 推荐主流方案 → 更多人用 → 产生更多数据 → AI 更爱推荐

你让 AI 帮你写代码,它大概率会给你:

  • 用老版本语言特性写的代码
  • 保守、传统的实现方式
  • 基于大量历史案例的「稳妥」方案

碰到小众语言或新特性,AI 立马就不行了,错误率蹭蹭往上涨。这就形成了一个恶性循环,强者愈强,创新愈难。

机器学习算法走进酒吧

Kevlin 讲了个特别妙的段子:

一个机器学习算法走进酒吧。 酒保问:「您要什么?」 算法回答:「大家都在喝什么?」

这个段子完美地说明了 LLM 的本质:它们不会创造,只会根据统计规律做模式匹配和重组。用到编程语言选择上,这意味着:

  • 已经占主导地位的语言将继续占主导地位
  • 新语言面临更高的进入门槛
  • 创新将主要发生在语法糖和工具链层面,而非根本性变革

未来已来,只是分布不均

William Gibson 的名言「未来已经到来,只是分布不均」在编程语言领域有着特殊的含义。我们以为的「创新」,很多时候只是在重新发现过去:

被重新发现的轮子

「现代」特性 实际诞生年份 首次出现
协程 1958 Melvin Conway
块结构 1960 ALGOL 60
多重赋值 1963 CPL
迭代器/yield 1974 CLU (Barbara Liskov)
管道操作 1964 Doug McIlroy
模式匹配 1973 ML
可选分号 1970s CLU
Lambdas 1936 Alonzo Church

我们并非在发明未来,而是在缓慢地重新实现过去。每一代程序员都在「发现」这些概念,就像 Columbus「发现」美洲一样。

为什么进化如此缓慢?

// 编程语言进化的阻力因素
enum EvolutionResistance {
    LegacyCodebase {
        lines_of_code: u64,  // 数十亿行的遗留代码
        migration_cost: Cost, // 天文数字的迁移成本
    },
    HumanFactors {
        learning_curve: Duration,     // 学习新语言的时间成本
        team_coordination: Complexity, // 团队协调的复杂度
        mental_models: Inertia,       // 思维模式的惯性
    },
    EcosystemLock {
        libraries: Vec<Dependency>,   // 庞大的生态依赖
        tools: Vec<Tool>,            // 工具链锁定
        platforms: Vec<Platform>,     // 平台兼容性
    },
    SocialDynamics {
        network_effects: Strength,    // 网络效应
        job_market: Demand,          // 就业市场需求
        community_size: usize,        // 社区规模
    },
}

编程语言的进化面临着多重阻力:

  1. 遗留系统的引力:全球有数十亿行 COBOL 代码仍在运行关键金融系统
  2. 生态系统锁定:一门语言的价值不在语言本身,而在其生态系统
  3. 认知惯性:改变思维模式比学习新语法困难得多
  4. 网络效应:使用者越多,语言越有价值,越难被替代

深度思考:编程的本质是什么?

在这个 AI 辅助编程盛行的时代,Kevlin 的演讲促使我们思考一个根本问题:编程的本质是什么?

语言作为思维工具

编程语言不仅是我们与计算机对话的工具,更是我们思考问题的框架。Sapir-Whorf 假说认为,语言塑造思维。在编程领域,这个假说有着切实的体现:

  • C 程序员 倾向于思考内存布局和指针
  • Lisp 程序员 自然地想到递归和列表处理
  • Haskell 程序员 用类型和纯函数构建心智模型
  • Rust 程序员 关注零成本抽象和并发安全
  • Go 程序员 用 channels 和 goroutines 思考并发

简约(Simplicity)的价值

Tony Hoare 于图灵奖演讲「The Emperor’s Old Clothes」曾说:「软件设计有两种方式:一种是设计得如此简单以至于明显没有缺陷,另一种是设计得如此复杂以至于没有明显的缺陷。」

现代编程语言的发展趋势似乎倾向于后者。C++ 标准已经厚到「拥有自己的引力场」,JavaScript 每年都在添加新特性,即使是曾经简洁的 Python 也在变得越来越复杂。

但真正持久的创新往往来自简化而非复杂化:

// 简单性的力量:Unix 管道哲学
// 每个程序只做一件事,但做到极致
fn word_frequency(text: &str) -> HashMap<String, usize> {
    text.split_whitespace()
        .map(|word| word.to_lowercase())
        .fold(HashMap::new(), |mut acc, word| {
            *acc.entry(word).or_insert(0) += 1;
            acc
        })
}

未来的编程范式?

如果说过去 60 年的编程语言进化给我们什么启示,那就是:真正的范式转换极其罕见。

我们仍在使用:

  • 1960 年代的控制结构
  • 1970 年代的抽象机制
  • 1980 年代的对象模型
  • 1990 年代的泛型编程

即使是看似革命性的创新,如响应式编程、函数响应式编程、Actor 模型等,其根源都可以追溯到几十年前。

实践启示:如何在慢进化时代做出明智选择

1. 选择无聊的技术

「Choose Boring Technology」不是保守,而是智慧。无聊意味着:

  • 稳定的语言规范
  • 成熟的生态系统
  • 丰富的学习资源
  • 可预测的未来

2. 深度优于广度

与其追逐每个新语言和新框架,不如深入理解少数几个:

// 深入理解内存模型比学习十种语言的语法更有价值
use std::rc::Rc;
use std::cell::RefCell;

// 理解为什么需要 Rc<RefCell<T>>
// 比知道十种语言的智能指针语法更重要
type SharedMutable<T> = Rc<RefCell<T>>;

3. 原理优于特性

理解编程语言背后的原理比掌握具体特性更重要:

  • 理解闭包的本质,而不只是语法
  • 理解类型系统的理论,而不只是用法
  • 理解并发模型的权衡,而不只是 API

4. 拥抱「够用」哲学

完美是优秀的敌人。在编程语言选择上:

  • 够用的语言 + 优秀的设计 > 完美的语言 + 糟糕的设计
  • 团队熟悉的语言 > 理论上更好的语言
  • 有活跃社区的语言 > 技术上更先进但小众的语言

结语:在重力场中翱翔

回到 Kevlin 的隐喻:编程语言就像重力,无处不在,塑造一切,但往往被忽视。我们无法摆脱重力,但可以学会在其中优雅地翱翔。

编程语言的进化可能永远不会像我们期望的那样快,AI 的介入可能让这个过程更加保守。但这未必是坏事。稳定性带来了可预测性,保守性确保了兼容性,缓慢的进化让我们有时间真正理解和掌握工具。

正如 Bjarne Stroustrup 所说:「只有两种编程语言:一种是人们抱怨的,另一种是没人用的。」我们使用的语言都不完美,但它们足够好,足够稳定,足够强大,让我们能够构建改变世界的软件。

在这个 AI 辅助编程的新时代,理解编程语言的历史、现状和未来趋势,比以往任何时候都更重要。不是因为我们需要预测下一个「大语言」,而是因为我们需要理解:真正的创新不在于语言本身,而在于我们如何使用它们来表达思想、解决问题、创造价值。

未来的编程语言可能不会有革命性的变化,但未来的程序员 —— 懂得历史、理解原理、拥抱简单、追求本质的程序员 —— 将创造真正的革命。

「过去从未死去,它甚至从未过去。」 —— William Faulkner

在编程语言的世界里,这句话有着特别的含义:我们以为的创新,往往是对过去的重新发现;我们期待的未来,可能早已在某个尘封的论文中等待;而我们每天使用的工具,承载着半个多世纪的智慧结晶。理解这一点,也许是成为更好程序员的第一步。

MORE IN 编程语言与工程

同专栏延伸阅读

查看「编程语言与工程」全部文章 →

是时候认识 jj 了:Git 的下一个进化方向

Git 统治了版本控制二十年,但它的暂存区、脆弱的 rebase、动辄阻断的合并冲突,正在成为 AI 时代的绊脚石。jj 从底层重构了版本控制的心智模型,而且完全兼容 Git。这篇文章带你看清它为什么值得关注。

New Hope (2025–2026)5,588 字 · 12 分钟

为什么有的语言「不能」编译成 WebAssembly?

在上一篇文章「dart:失之东隅收之桑榆」里,我写了这样一句: dart 也许未来可以支持 WebAssembly(类似 golang,有没有意义再说);而 TypeScript 没有这种可能。 于是很多 TypeScript 的拥趸不开心了,为什么说我家宝宝不能支持 WebAssembly(下文称 WASM)?有人找出了证据:看,AssemblyScrip…

天叔奇谈 (2013–2020)4,878 字 · 11 分钟