开发者 Scott O. 在个人博客 scotto.me 发了一篇长文,回应一个论坛老问题:学 Lisp,到底该先学哪个方言。他的答案不算讨巧——方言重要,但没有初学者想象的那么重要。
真正决定长期走向的,是 Common Lisp 的原生性能和稳定标准,还是 Clojure 的 JVM 生态和已有代码库。这个判断听着轻松,但对准备把代码跑进生产环境的团队,选型仍然是一笔要算清楚的账。
Lisp 不是一门语言,是一个方言家族
Wikipedia 列出的 Lisp 方言超过 20 种。它们共享最基本的括号语法,但语义、标准库和运行时完全不同。
这和 Python 有 CPython、PyPy 两种实现却还是同一门语言,是两回事——Lisp 的分裂发生在语言规范层面,不是实现层面。
Scott O. 认为,初学者要学的其实是 Lisp 式的编程思维,用哪个方言入门都能学到,换方言的成本也不高。这对只想搞懂范式的个人学习者基本成立;但对要长期维护代码的团队,方言差异不能一句话带过。
Common Lisp 与 Clojure:分野在运行时
Common Lisp 于 1994 年形成 ANSI 标准,是家族里最老资格的一支。主流实现 SBCL 能直接编译成原生代码。
Clojure 由 Rich Hickey 在 2007 年推出,起因是客户不放心用 Common Lisp、坚持要 Java 或 C#,他索性写了一门能编译成 JVM 字节码的 Lisp,直接调用 Java、Kotlin、Scala 写的现成库。
两者的核心差异不在语法,在运行时能给你什么、又要你付出什么:
| 维度 | Common Lisp | Clojure |
|---|---|---|
| 标准/血统 | 1994 年 ANSI 标准 | 2007 年发布,非正式标准 |
| 主要实现 | SBCL,编译原生代码 | 官方 Clojure,编译 JVM 字节码 |
| 生态 | 独立生态,规模小、社区分散 | 直接复用 Java/Kotlin/Scala 库 |
| 调试 | 条件系统 + 运行中 REPL 调试 | 依赖 JVM 工具,报错常混杂 Java 栈信息 |
| 并发 | 标准里没有内建并发原语 | atom/ref/agent + 不可变数据结构 |
| 启动开销 | 低 | 有 JVM 启动和调优成本 |
Common Lisp 换来的是标准稳定和原生性能,代价是社区分散、教程要么太浅要么太深。Clojure 换来的是现成的 Java 生态和并发工具,代价是调试时要啃一截 JVM 栈追踪,上线前还得懂点 JVM 调优参数。
谁该纠结,谁可以先学再说
只想搞懂 Lisp 范式的初学者,挑手边资源顺手的入门书就够了——《Practical Common Lisp》还是《Land of Lisp》,差别不大,不必为选错方言焦虑。
已经跑在 JVM 上、团队里有 Java 或 Kotlin 遗留代码的技术负责人,情况不同。这时候方言选择不再是学习曲线问题,而是能不能接受 JVM 启动开销、调优复杂度,以及排查故障时能不能看懂夹杂 Java 信息的报错栈。想写独立命令行工具、追求低启动延迟的个人项目,Common Lisp 配 SBCL 编译成原生可执行文件更直接,不用背 JVM。
原文提到 Grammarly、Google 早期的 Flight Search、Netflix、Apple 等采用过 Clojure 或 Common Lisp,这类记录多来自过去某个阶段的技术选型,不能当作这些公司目前仍在生产环境大规模使用的证据,更适合当背景参考。
值得留意的是,Clojure 社区一直在尝试用 GraalVM 原生镜像解决 JVM 启动慢的老问题。如果这条路径进一步成熟,Common Lisp 在启动速度上的优势会被拉近,这也是接下来判断两门语言差距时最该盯的变量。
