第 1 部分 · 起点:编程与计算的本质
Racket 不是教学语言
很多人第一次听说 Racket,是在某门编程入门课上。于是它被贴上一个标签:“教学语言”——言下之意,玩具、不顶用。这个标签错得离谱。
如果我问你,哪门语言能做这些事:
- 给 iOS 和 macOS 应用嵌入一个跨语言的运行时
- 跑起一个能扛流量的现代 Web 服务
- 打包成一个双击就跑的桌面应用,Windows、macOS、Linux 全覆盖
- 定义你自己的编程语言,连语法都由你说了算
你大概会猜 Rust、Go、Python 里的某一个。答案里有一个是 Racket——而且它把这四件事都做到了。这本书要教的就是这门被严重低估的语言。
“教学语言”这个标签,从哪来的
Racket 背这个名声不是没来由。它的前身叫 PLT Scheme,1990 年代由 Matthias Felleisen 的团队创造,明确的目的就是教书——为一门叫《How to Design Programs》的入门课配的语言和环境。
它自带的开发环境 DrRacket,从一开始就是为新手设计的:界面干净、错误信息讲人话、两扇窗(写代码和立即试)的结构让初学者不容易迷路。
所以“教学语言”这个印象,是 Racket 主动选的出身,不是它的能力上限。问题出在很多人把“为教学而设计”和“只能用于教学”画了等号。这是两件完全不同的事。
为教学而设计,意味着它把概念讲得清楚、把错误提示做得友好、把环境调得不吓人。这些品质,恰恰是工业级开发最稀缺的。 你见过多少“工业级”语言,错误信息像天书、配置复杂到劝退、文档残缺不全?
Racket 因为从教学起步,反而避开了这些坑。到 2010 年它正式从 Scheme 改名 Racket 时,已经长成一门完整的、能用于真实生产的语言平台。
要理解 Racket 的来历,得往上追两步。1958 年,John McCarthy 创造了 Lisp——历史上第二古老的高级语言,仅次于 Fortran。Lisp 用一种叫 S-表达式的语法,把“代码”和“数据”统一成同一种结构。这个设计前卫到六十年后的语言还在追赶它。
Lisp 后来分化出很多方言,其中一种叫 Scheme,以简洁著称。Racket 就是 Scheme 的直系后裔——所以你在这本书里会看到满屏的括号,那不是 Racket 的怪癖,是 Lisp 六十多年传下来的血脉。
不只是一门语言,是一个语言平台
理解 Racket 的关键,是意识到它不只是“又一门编程语言”。
大多数语言给你一套固定的语法和功能,你用它写程序。Racket 不一样:它是一个用来造编程语言的平台。官方自己的说法是,Racket 是“一门用来创造编程语言的编程语言”。
这件事从文件第一行就能看出来。打开任何 Racket 文件,第一行都是 #lang 开头——它声明“这个文件用什么语言写”:
#lang racket ; 用标准 Racket
#lang typed/racket ; 用带静态类型的 Racket
#lang scribble/base ; 用 Racket 的文档语言
换一行 #lang,就是换一门语言。这不止是切换语法——typed/racket 会给你完整的渐进式类型系统,scribble 是专门写文档的语言。更关键的是,你还能自己写一个 #lang,定义一门全新的、为你的问题量身定做的语言。
[架构图:Racket 语言平台的三层结构。顶层是各种 lang 声明的语言(racket / typed/racket / scribble / 自定义语言),中间是统一的 Reader-Expander-Runtime 管线,底层是 Racket 运行时。强调“换 lang 声明换语言,底层共用”]
这就是 Racket 和绝大多数语言的根本区别:别的语言语法是定死的,Racket 的语法是可造的。宏让你扩展语法,DSL 让你为某个领域定制小语言,#lang 让你定义全新语言。当你在别的语言里抱怨“要是有这样的语法就好了”,在 Racket 里你能直接把它造出来。这本书的卷六会带你亲手走一遍这条路。
这套能力不是花架子。Racket 团队经过 20 多年实践,把它做成了一个能快速设计、部署新语言的完整工程系统——带着契约系统、渐进式类型、出色的文档体系。这些是实打实的工程能力,不是教学演示。
它真的能跑在生产环境
光说能力不够,得看真东西。Racket 在生产环境有几个很有说服力的真实案例。
Noise:跨语言的嵌入式运行时。 Bogdan Popa 是 Racket 社区最活跃的贡献者之一。他用 Racket 造了一个叫 Noise 的项目——一套类型安全、支持异步的嵌入式后端架构。
简单说,它让你能把 Racket 运行时嵌进 iOS、macOS 的原生应用里,让 Swift 和 Racket 互相对话。这不是玩具:它有完整的三层架构(C 层运行时、二进制序列化协议、管道通信的执行模型),能编译成多平台的二进制框架分发。
一本书要用实例证明“这门语言能打工业级”,Noise 是最好的证据之一——这本书的卷七会带你精读它的源码。
Koyo:现代 Web 框架。 同一个作者还维护着 Koyo,一个基于 Racket 的 Web 应用开发工具包。它不只是包装了 Racket 内置的 Web 服务器,而是提供了一整套开箱即用的现代 Web 应用所需的组件——而且组件之间是解耦的,想用什么用什么。
Racket 的 Web 框架还有一个独门绝技:基于延续(continuation)的会话管理,能在无状态的 HTTP 协议上写出像有状态对话一样的代码。这是别的语言很难复刻的能力,卷七会展开讲。
打包和部署,一条龙。 写完程序得能发出去。Racket 的 raco exe 能把代码、依赖的库和运行时打包成一个单一的可执行文件——目标机器上不用装 Racket 就能跑。raco 还能进一步打成 Windows、macOS、Linux 三平台的安装包。
不喜欢打包成可执行文件?Racket 也能容器化:用 Dockerfile 把 Racket 应用做成可移植镜像,跑在云原生环境里。这两条部署路径,正好覆盖“单文件分发”和“微服务上云”两种主流场景。
ActivityLog2:真实的开源桌面应用。 这是一个基于 Racket GUI 的开源项目,是个完整的原生桌面应用。它证明了 Racket 的 GUI 工具包不止能写教学小程序,也能撑起一个有实际功能的产品。卷七会带你把它从头构建运行起来。
那为什么它还是最佳入门语言
到这里你可能会想:既然 Racket 这么能打,为什么不直接说它是“工业级语言”,还要强调教学?
因为它最特别的地方,正是把教学的友好和工业的能力揉在了一起。这两样在大多数语言里是分开的——对新手友好的往往简单到干不了正事,能干正事的往往把新手挡在门外。Racket 是少有的同时满足两头的语言。
对新手,它有 DrRacket 这个为学习设计的环境、清晰到惊人的错误信息、REPL 式的“边跑边学”。对老手,它有宏、延续、契约系统、渐进式类型——这些都是编程语言理论里最深刻的概念,Racket 把它们做成了能上手把玩的东西。你用一门语言,就能从“什么是编程”一直走到“怎么造一门语言”,中间不用换车。
还有一点很实在:Racket 的三范式都原生支持。函数式、命令式、面向对象——通常你得分别去学 Haskell、C、Java 才能体会,Racket 在一个地方让你看清三种范式各自的长处和短处。这本书就是沿着这条路设计的。
这本书会带你走多远
所以,这本书的承诺是两头的:
- 如果你完全没编过程,它能把你带进门,而且带你进门的方式是真正理解,不是背语法
- 如果你已经有经验,它能让你掌握 Racket,并用它做出成熟的应用
从卷一的“编程是什么”,到卷六的“造你自己的语言”,再到卷七的 Web、数据、打包部署——这是一条从第一行代码一直走到能上线产品的完整路径。每一章都讲清楚为什么,不让你背任何一句咒语。
下一篇是个选读:我们把“电脑到底在干什么”这个问题再往深里挖一层,看看半个多世纪前两个数学家——图灵和丘奇——是怎么回答它的。那一章理论性最强,但它是你后面写的每一行代码的祖宗,值得花一趟能看清全貌。