Scheme
Scheme 是一种属于 Lisp 语言家族的编程语言,由盖伊·史提尔与杰拉德·杰伊·萨斯曼于 1975 年在麻省理工学院开发,与 Common Lisp 并列为 Lisp 的两大主要方言。它遵循极简主义设计,以规模很小的语言核心配合宏等扩展机制构成整体,并较早引入词法作用域、头等续体与卫生宏等特性,长期被用于计算机科学教学与研究。
定义
Scheme 是 Lisp 家族中的一种方言,与 Common Lisp 一同被视为该家族的两支主要分支。它采用静态作用域规则,程序与数据都以括号包裹的 S-表达式书写,源代码可以直接当作数据被读取和改写[1][2]。
与多数早期 Lisp 方言不同,Scheme 强调语言核心应当尽量小,标准只规定少量语法形式与基本过程,其余能力依靠宏和库扩展[3][1]。这一取向常被概括为:语言设计不应靠不断堆叠特性,而应消除那些使额外特性显得必要的限制[4]。
在语言分类上,Scheme 属于多范式语言,支持函数式与命令式写法,具有动态类型和强类型检查,过程可作为值传递,文件扩展名通常为 .scm 或 .ss[1]。
原理
Scheme 的语义基础是 λ 演算。函数用 lambda 形式定义,函数调用与 λ 演算中的函数应用相对应,这使得语言的核心规则数量很少,却能组合出完整的计算能力[5]。变量遵循词法作用域,一处引用的绑定关系仅凭程序文本即可确定,无须考虑调用发生时的环境[6]。
求值模型上,Scheme 采用传值调用,并规定尾调用必须做尾调用优化:若过程调用位于尾位置,其调用者栈帧可被复用,因此可以用递归表达循环而不增长栈空间[3][2]。函数调用的算子位置与操作数位置按相同方式求值,全部变量共用同一个词法环境[2]。
另一项核心机制是头等续体。过程 call-with-current-continuation(常缩写为 call/cc)把当前计算的「剩余部分」打包成一个可调用过程交给用户过程,该过程日后被调用时,控制权会回到捕获点,且调用次数与时限不受限制[7]。常见实现方式是在捕获时复制当前调用栈,或在堆上分配调用帧,前者在未使用 call/cc 时不产生额外开销[8]。
宏系统以 syntax-rules 为代表,其展开遵循卫生性(hygiene)原则:宏模板中引入的标识符不会与使用处同名标识符意外冲突,因此可在保持词法绑定的前提下扩展语法[9][2]。
发展历程
Scheme 的源头可追溯至约翰·麦卡锡在 20 世纪 50 年代末设计的 Lisp,该语言用少量算子与借鉴自阿隆佐·邱奇 λ 记法的匿名函数,构造出图灵完备的系统[1][10]。1973 年,麻省理工学院的卡尔·休伊特提出演员模型,萨斯曼与史提尔为理解该模型在 Maclisp 环境中编写微型解释器,并由此意识到实现演员的关键在于把词法作用域引入 Lisp[1]。
1975 年,2 人完成新型 Lisp 解释器,并将在其上实现的演员模型微缩版命名为 Schemer,后因 ITS 操作系统文件名长度限制改称 Scheme[1]。同年 12 月,他们发表 AI 备忘录《Scheme: An Interpreter for Extended Lambda Calculus》,这是该语言的首次描述[11][12]。
1978 年,2 人发表《修订的 Scheme 报告:一种 LISP 方言》,随着麻省理工学院的实现升级为编译器,语言功能趋于完备,Scheme 由此被确立为 Lisp 的主要方言之一[12][1]。1981 年至 1982 年间,麻省理工学院、耶鲁大学与印第安纳大学各自开展项目,将 Scheme 的变体用于课程教学[12]。
由于各地实现逐渐分化,1984 年 10 月,15 个主要实现的代表集会,推动制定更广为接受的标准,随后选出由艾伦·鲍登、盖伊·史提尔与米奇·万德组成的指导委员会[12]。此后形成一系列名为《关于算法语言 Scheme 的第 n 次修订报告》的文件,通称 RnRS:R1RS 于 1978 年、R2RS 于 1985 年、R3RS 于 1986 年、R4RS 于 1991 年、R5RS 于 1998 年、R6RS 于 2007 年发布[4]。此外还有一份由电气与电子工程师协会批准的 IEEE 1178-1990 标准,内容接近 R5RS[13]。
R6RS 因体量较大、偏离极简取向而引发争议。2009 年,负责监督标准化的指导委员会提出将 Scheme 分为面向实用的大型语言与面向研究的小型语言两层[14]。小型层最终以 R7RS-small 形式于 2013 年 7 月定稿,而大型层至今仍在推进[13][15]。标准之外,社区还通过 SRFI(Scheme 实现请求)流程发展库层面的约定[16][17]。
在总结这段历史时,萨斯曼与史提尔于 1998 年表示,极简并非当初有意设定的目标,而是设计过程带来的意外结果:他们发现 λ 演算这一小而简单的形式系统足以充当富有表达力的语言核心[6]。
应用
Scheme 最主要的用途是计算机科学教育。麻省理工学院等院校曾用它讲授程序设计入门课程,教材《计算机程序的构造和解释》(SICP)即以 Scheme 阐释程序设计思想[1][18]。除 SICP 外,还有《Simply Scheme》等以该语言为教学载体的教材[19]。
在软件工程中,Scheme 常被嵌入宿主程序充当脚本或扩展语言。GNU 工程的 Guile 即为 Scheme 的一种实现,可作为库链接进应用程序,许多自由软件与开源软件将其作为内置脚本语言使用[20][21]。
该语言还用于人工智能与符号计算领域,例如交互式符号数学程序 JACAL 即以可移植 Scheme 写成,并依赖 SLIB 库[19]。由于头等续体可用来构造非局部退出、协程、异常处理等控制机制,Scheme 也常被当作研究控制流与编译技术的实验平台[7]。
局限
Scheme 的实现数量众多既是优势也是负担。不同实现之间的差异使代码移植困难,Scheme 指导委员会曾称其为「世上最不可移植的编程语言」,并认为它更像一个语言家族而非单一语言[1]。由于标准规定的库很少,实际开发往往需要先选定实现,可用库的范围随之确定[22]。
标准层面的分歧同样明显。R6RS 与 R3RS、R4RS、R5RS 不兼容,按早期标准编写的程序无法不加修改地在 R6RS 实现上运行[19]。R6RS 为禁止实现自行扩展词法与库语法而设的绝对要求,也使部分实现默认运行于非严格符合模式[23]。
在性能方面,早期实现多基于解释器,速度较慢;后续实现通过编译器优化改善了这一状况[3]。头等续体功能强大,但滥用会使程序控制流难以理解,有批评者将其形容为经过美化的 goto[8]。此外,极简标准与商用语言生态相比缺少统一的库集合与商业支持,这也是其在工业界应用范围有限的原因之一[22]。
参见
-
Lisp —— Scheme 所属的语言家族,其语法与同像性特征直接来自 Lisp。
-
Common Lisp —— 与 Scheme 并列的 Lisp 另一主要方言,设计取向偏重功能完备。
-
λ演算 —— Scheme 语义所依据的形式系统,函数定义与函数应用规则均源自于此。
-
计算机程序的构造和解释 —— 以 Scheme 为教学语言的程序设计入门教材。
-
GNU Guile —— Scheme 的一种实现,常用作自由软件的扩展与脚本语言。
-
续体 —— call/cc 所操作的对象,用于表达非局部控制流。
参考资料
- Scheme [引用日期2026-10-29]
- Introduction [引用日期2026-10-29]
- Scheme Basics (GNU Artanis web-framework Manual) [引用日期2026-10-29]
- latendresse-presentation(PDF) [引用日期2026-10-29]
- An Introduction to Scheme [引用日期2026-10-29]
- wiki [引用日期2026-10-29]
- Manual page for call-with-current-continuation(3scm) [引用日期2026-10-29]
- (syntax-rules () ; no other needed keywords [引用日期2026-10-29]
- \[\begin{array}{l} [引用日期2026-10-29]
- JavaScript disabled - The ACM Student Magazine [引用日期2026-10-29]
- SCHEME family [引用日期2026-10-29]
- Chapter 1 Historical background [引用日期2026-10-29]
- Scheme Standards [引用日期2026-10-29]
- wikipedia.org 上的网页 [引用日期2026-10-29]
- Recap of R7RS-small [引用日期2026-10-29]
- Scheme (程式語言) [引用日期2026-10-29]
- Re: Python syntax in Lisp and Scheme [引用日期2026-10-29]
- Gerald Jay Sussman [引用日期2026-10-29]
- Scheme is a computer programming language [引用日期2026-10-29]
- Scheme 语言概要(上) [引用日期2026-10-29]