简介
这本书描述了 Chez Scheme 给 Scheme 修订6报告 (R6RS) 的扩展。它也 包含了对标准对精确对概括和 Chez Scheme 的句法形式和过程,并给出了每个句法形式的句法 和每个过程所接受的参数数量和类型。R6RS 标准特性的细节可以在 《Scheme 编程语言,第四版》 (TSPL4) 或 Scheme 修订6报告 里找到。《Scheme 编程语言,第四版》也包含了大量的对 Scheme 语言的介绍和许多或短或长的例子。
这个文档的大部分也可以同样地应用于 Petite Chez Scheme,它可以完全兼容整个 Chez Scheme 系统,只不过使用了很快的解释器代替了 Chez Scheme 的增量式原生代码编译器。 只要不涉及编译器调用,那么给 Chez Scheme 写的程序可以原封不动地运行于 Petite Chez Scheme 里。 事实上,Petite Chez Scheme 和 Chez Scheme 构建于相同的源代码,除了包含编译器代码, 其它的都一样。在2.8节,详细地讨论了这个差别的影响。
本章剩下的部分包括 Chez Scheme 对 Scheme 句法的扩展 (第1.1节),本书用到的符号约定 (第1.2节), 用来定制系统的行为界限 (第1.3节),和在哪里可以找到更多关于 Chez Scheme 的信息 (第1.4节)。
第二章描述了如何用 Chez Scheme 开发程序,写脚本,交付应用,加上如何使编译器尽可能 生成更高效的代码。第三章描述了调试和对象检查工具。第四章记录了用于和不同进程或其它语言写的 代码如何交互的文档。第五章描述了绑定句法形式。第六章记录控制结构的文档。第七章记录了非数值 对象的操作的文档,而第八章记录了多种数值操作,包括高效的类型明确的操作。第九章描述了输入/输出 操作和一般性端口,一般性端口允许通过任意的输入输出语义来定义其它端口。第十章讨论了 R6RS 库 和顶层程序如何加载进 Chez Scheme,并可同时使用其众多的用于控制和追踪加载进程的特性。第 十一章描述了句法扩展和模块。第十二章描述了系统操作,例如与操作系统的交互和定制 Chez Scheme 的用户接口。第十三章描述了如何调用和控制存储管理系统和记录了守卫者和 weak pair 的文档。第十四章描述了 Chez Scheme 的表达式编辑器和如何定制它。第十五章记录了构成 Chez Scheme 原生线程 系统接口的过程和句法形式。最后,第十六章描述了很多兼容特性。
这本书后面包含了参考书目,句法形式的总结,和索引。出现在句法形式总结中的页码和出现在索引中的 斜体页码指出了句法形式和过程在文中正式地被定义的位置。句法形式总结和索引包含了来自 TSPL4 的 条目,因此它们包含了 Chez Scheme 整个的特性集合。TSPL4 条目的页码标记有前缀“t”。
这本书和 TSPL4 的在线版本和勘误可以在这里找到 www.scheme.com。
感谢:Michael Adams, Mike Ashley, Carl Bruggeman, Bob Burger, Sam Daniel,
George Davidson, Matthew Flatt, Aziz Ghuloum, Bob Hieb, Andy Keep,
和 Oscar Waddell 对开发 Chez Scheme 作出的重大贡献。Chez Scheme 的表达式编辑器
基于 C. David Boyer 从 1989 年到 1994 年开发的给 Scheme 的命令行编辑器。文件压缩用到
了 Jean-loup Gailly 和 Mark Adler 开发的 zlib 压缩库。实现 list 和 vector
排序的子程序基于 Olin Shiver 的机会主义合并排序算法和实现。Michael Lenaghan 为本书
的早期草稿提供了若干修正意见。这本书记录的很多特性都是现在的 Chez Scheme 用户建议的,
并且用户的许多评论也提升了本书,在正文内容方面。欢迎提出更多可以提升 Chez Scheme 和本书
的意见。
1.1 节 Chez Scheme 句法
Chez Scheme 在对象 (数据) 和句法形式层面都继承自 Scheme。在对象层面上,Chez Scheme
支持包含非标准字符的额外的符号表示,非十进制的浮点数和科学记法,显式长度的 vector,共享的
和循环的 structure,record,box 等等。接下来将描述这些扩展。句法形式层面的扩展
将会在贯穿全书和句法形式总结中描述,书后面也会出现。
Chez Scheme 以若干方式方法继承了标识符的语法。首先,组成标识符名字的字符序列可以以数字,句号,
加号和减号开头,只要这个序列不被解析为数字就可以。举个例子,0abc,+++,和 .. 在
Chez Scheme 里均是有效的标识符。其次,单字符序列的 { 和 } 也是标识符。再次,包含任意
字符的可能会被用 \ 或 | 转义后打印。\ 用于转义单字符(除了 ‘x’,因为 \x 用于标记十六进制
标量值的开头),而 | 被用来转义一组跟着它到匹配到下个 | 的字符。举个例子,\||\| 是一个
名字包含两个字符,由字符 | 后跟字符 \ 组成的标识符,|hit me!| 是一个名字中包含一个空白的标识符。
另外,gensym 会打印出用 #{ 和 } 括号括起来的“美观”和“独特”的两种名字,例如,
#{g1426 e5g1c94g642dssw-a}。也可以只用带前缀 #: 的“美观”名字打印,例如 #:g1426。
从 2 到 36 的任意基数可以用 #nr 来指定,这里的 n 是基数。大小写不重要,因此,使用 #nR 也是
一样的。数字值从 10 到 35 也可以用或小写或大写到字母字符来指定,就像十六进制数字那样。举个例子,
#36rZZ 就是 35 × 36 + 35 或 1295。
Chez Scheme 也允许非十进制数字打印成浮点数或科学记法。举个例子,#o1.4 等于 1.5,
#b1e10 等于 4.0。数字优先于指数符号,因此,#x1e20 就只简单的是四个数的十六进制数字,等于
7712。
另外,附加了一些除标准知名字符如 #\alarm, #\backspace, #\delete, #\esc,
#\linefeed, #\newline, #\page, #\return, #\space, 和 #\tab 之外,
Chez Scheme 还可以识别 #\bel, #\ls, #\nel, #\nul, #\rubout,
和 #\vt (或 #\vtab)。标量值小于 256 的字符也可以以八进制语法即由前缀 #\ 后跟一个三个八进制
数字的序列打印。举个例子,#\000 等于 #\nul。
Chez Scheme 的 fxvector,或者固定数 vector,将以类似 vector 但用前缀 #vfx( 代替了
#( 打印。vector,bytevector 和 fxvector也可以以显式长度前缀打印,并且当指定了显式长度前缀,
尾部重复元素也将被省略。举个例子,#(a b c) 也可以打印成 #3(a b c),长度 100 元素全是零的 vector
可以打印成 #100(0)。
Chez Scheme 的 box 将以 #& 前缀打印,例如,#&17 是一个包含整数 17 的 box。
record 将以 #[类型名 数据成员 ...] 的语法打印,这里的符号 类型名 是 record 类型的名字,
field ... 是 record 的数据成员内容的打印表示。
共享结构可以打印为前缀 #n= 的图标记,循环结构可以打印为前缀 #n# 的引用。#n= 用来标记东西作为
输入,#n# 用来引用标记为 n 的东西。举个例子,'(#1=(a) . #1#) 是一个 pair,其 car 和
cdr 乃同一个列表,#0=(a . #0#) 是一个循环列表,也就是说,它的 cdr 是它自己。
$primitive 形式也可以像 quote 一样可以简写,用前缀 #%。举个例子,#%car 等价于
($primitive car),#2%car 等价于 ($primitive 2 car),#3%car 等价于 ($primitive 3 car)。
Chez Scheme 的文件结束对象打印为 #!eof。如果文件结束对象出现在正被加载的文件中的任何数据对象之外,
load 将以文件真正结束对待,即在这个点停止加载。因此可以通过在文件中间插入 #!eof 来方便地追踪加载时错误。
Weak pair 中损坏的指针表示为 broken weak pair 对象,打印为 #!bwp。
作为对标准分割符(空白,开闭圆括号,开闭方括号,双引号,分号和 #)的补充,Chez Scheme 也可以将开闭花括号,
单引号,反引号,逗号视作分割符。
在输入流中看到 #!r6rs 注释指令后,上面描述的 Chez Scheme 的词法扩展将失效,除非在之前看到 #!chezscheme
指令。每个通过 import 隐式加载的库和每个通过 --program 命令行选项,scheme-script 命令,或 load-program
过程加载的 RNRS 顶级程序都将会以它以隐式的 #!r6rs 注释指令开头来对待。
按照修订报告6的要求,符号和字符名字的大小写通常都是重要的。在相同的输入流里,就像被 string-foldcase处理过
一样,#!fold-case 注释指令后的名字都是小写的,除非看到 #!no-fold-case。没有指令的时候,且 case-sensitive
行为界限被设置成 #f 时,名字也都是小写的。
打印机被 write, put-datum, pretty-print, 和 format ~s 选项调用总是用标准语法打印修订报告6
的标准对象,除非通过设置一个打印行为界限来请求不同的行为。举个例子,要使用上面描述的十六进制标量值转义序列来打印
Chez Scheme 扩展标识符语法的符号, 除非设置 print-extended-identifiers 行为界限为真。类似的,除非设置
print-vector-length 行为界限为真,否则不会打印显式长度或抑制尾部重复元素。
1.2 记号惯例
本书跟《Scheme 编程语言,第四版》使用了几近相同的记号惯例。下面重复了这些惯例和 一些 Chez Scheme 特有的标注。
当说一个过程或句法形式产生的值是 未确定的 ,那么这个过程或形式也许返回了任意数量的值,每个都是任意 Scheme 对象。
当结果是非确定的时,Chez Scheme 常会返回仅有一个,独一无二的 空 对象 (参见 void);然而,尤其当你的程序要移植到
其它的 Scheme 实现时,应该避免算上这个行为。Chez Scheme 的 waiter (读-求值-打印循环,REPL) 会抑制打印空对象。
这本书用“必须”和“应该”这样的词来描述程序的需要,例如调用 vector-ref 时需要提供一个小于 vector 长度的索引。如果
用了“必须”一词,那意味着这个需要是该实现强制的,即会抛出异常,常使用 condition 类型 &assertion。如果用了
“应该”一词,那么异常可能会也可能不会被抛出。如果未抛出,那么该程序的行为则是未确定的。短语“句法违规”用来描述程序
畸形时的情况。句法违规在程序执行前会被发现。当发现句法违规时,程序将抛出 &syntax 类型的异常,并停止执行。
Scheme 对象显示为 打字机 字体,就像它们是在键盘上按出来的一样。这些对象包括标识符,常量对象,括起来的 Scheme 表达式,和
整个程序。斜体字体用来衬托句法形式和过程描述中的句法变量。当斜体字首次出现时,也用斜体字来作衬。标识符的首字母通常不会大写,
即使出现在句首也不会大写。这对写作斜体字的句法变量来说也是一样的。
在描述句法形式和过程时,是用一个模式来展示句法形式和过程应用的。句法关键字和过程名是以打字机字体给出的,圆括号也是。句法或 参数剩余的片段,用来暗示句法形式或过程要求的表达式或参数类型的名字都用斜体展示。
1.3 行为界限
所有 Chez Scheme 的系统定制都是通过 行为界限 来完成的。行为界限是一个封装了隐藏的状态变量的过程。当无参调用时将返回 封装的变量的值。当以一个参数调用时,行为界限将改变这个变量的值为参数的值。当它的参数不合适时,行为界限可能会抛出异常, 或者可能以某种方式过滤这个参数。
新的行为界限可能被运行于 Chez Scheme 的程序所创建和使用。使用行为界限而不是全局变量来让程序定制具体行为有两个原因:
首先,非故意的重定义一个定制变量会导致不可预料的问题,然而,非故意的重定义行为界限只简单地使行为界限不可触及。举个例子,
一个程序因为自己的目的定义了 *print-level* 并在 Chez Scheme 里提早声明,这将导致在打印 Scheme 对象时
一些不可预料的影响,然而,一个程序因为自己的目的定义了 print-level 行为界限,只是简单地损失了改变打印机行为的能力。
当然,一个程序调用这个 print-level 也仍然会以未计划的方式影响这个系统,发生事故,但这种事更少发生,而且只会出现在
一个不正确的程序之中。
其次,给行为界限无效的值在“赋值”时会被立即发现并拒收,而不是在第一次使用时的点上出现,那样找回并恢复旧值就太晚了。举个例子,
给 *print-level* 赋值为 -1 将不会被捕获直到首次调用 write 或 pretty-print,然而当尝试将 -1 赋值给行为界限
print-level 时,即 (print-level -1),就会在真的发生改动之前,立即出现一个错误信号。
内置的系统行为界限在贯穿这本书的各个章节都会被描述,并在这本书后面形式总结中的其它句法形式和过程中被列出。在线程版的 Chez Scheme 中,标记为“线程行为界限”的行为界限,各线程有各自的值,然而标记为“全局行为界限”的行为界限的值将被所有的线程共享。非线程 版本的 Chez Scheme 不能分辨线程和全局行为界限的差别。参见第 12.13 节和第 15.6 节来获取创建和操作行为界限的更多信息。
1.4 更多信息
下面列出了记录了很多 Chez Scheme 和其实现的特性文章和技术报告:
- 句法抽象 [14,8,17],
- 模块 [32],
- 库 [21],
- 存储管理 [12,13],
- 线程 [10],
- 多返回值 [2],
- 可选参数 [16],
- continuation [7,25,3],
- eq? 哈希表 [20],
- 内部定义, letrec, 和 letrec* [33,22],
- equal? [1],
- 引擎 [15],
- 浮点数打印 [4],
- 代码生成 [18],
- 寄存器分配 [6],
- 过程内联 [31],
- 性能分析 [5],和
- 实现的历史 [9]。
这些出版物的摘要和电子版本可以在 http://www.cs.indiana.edu/chezscheme/pubs/ 获取。
译注:上面的方括号内的数字索引对应的位置可以在这里找到相应的信息。
思科系统公司版权所有 © 2018
按 Apache License Version 2.0 授权 (完整的版权公告)
为 Chez Scheme 9.5.1 版本修改于 2018 年十月