第一章 介绍
本书介绍了Chez Scheme对Scheme [28] (R6RS) 的修订报告6的扩展。还包含其标准和Chez Scheme形式和过程的摘要,其中给出了每种形式的语法以及每个过程所接受的参数的数量和类型。 有关标准R6RS功能的详细信息,请参见The Scheme Programming Language, 4th Edition (TSPL4) [11],或者Scheme的修订6报告。The Scheme Programming Language, 4th Edition还包含对Scheme语言的广泛介绍以及众多简短示例。
本文档的大部分内容也同样适用于Petite Chez Scheme,它与完整的Chez Scheme系统完全兼容,但使用高速解释器代替Chez Scheme的增量native-code编译器。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节)。
第2章介绍了如何使用Chez Scheme进行程序开发,脚本编写和应用程序交付,以及如何使编译器生成尽可能高效的代码。第3章介绍调试和对象检查功能。第4章介绍与不同进程或用其他语言编写的代码进行交互的功能。第5章介绍绑定形式。第6章介绍了控制结构。第7章介绍了对非数字对象的操作。而第8章介绍了各种数字操作,包括有效的特定于类型的操作。第9章介绍了输入/输出操作和通用端口,它们允许使用任意输入/输出语义定义端口。第10章讨论如何将R6RS库和顶层程序加载到Chez Scheme中,以及用于控制和跟踪加载过程的各种功能。第11章介绍语法扩展和模块。 第12章介绍了系统操作,例如与操作系统和自定义Chez Scheme用户界面的交互操作。第13章介绍如何调用和控制存储管理系统并描述守护者和弱对。第14章介绍了Chez Scheme的表达式编辑器以及如何对其进行自定义。第15章介绍构成Chez Scheme本地线程系统接口的过程和语法形式。第16章介绍了各种兼容性功能。
本书的背面包含目录,表格摘要和索引。出现在表格摘要中的页码和出现在索引中的斜体页码表示正式定义表格和程序的文本位置。 表单和索引的摘要包括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在对象(datum)级别和句法形式级别都扩展了Scheme的语法。Chez Scheme支持了对于字符的额外表示,其中包含非标准字符,浮点数和科学计数法,显式长度的vector,共享的和循环的structure,record,box等等。这些扩展将在下面描述。形式级别扩展将贯穿整本书,并在《表单摘要》中进行了总结,该摘要也出现在本书的背面。
Chez Scheme以多种方式扩展标识符的语法。首先,组成标识符名称的字符序列,可以以数字,句点,加号和减号开头,只要该序列不能解析为数字即可。例如,0abc,+++和..在Chez Scheme中都是有效的标识符。其次,单字符序列{ and }是标识符。 第三,包含任意字符的标识符可以通过用\或|进行转义来打印。 \ 用于转义单个字符('x'除外,因为\x表示十六进制标量值的开始),而 | 用于通过匹配 | 来使跟在其后的字符组转义。例如 \||\|
是一个标识符,具有两个字符的名称,由字符 | 组成。|hit me! |
是一个标识符,其名称包含空格。
此外,gensyms(第7.9节)上用 #{and}
括号打印,括号中同时包含“漂亮”且“唯一”名称,如:#{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, and #\vt (or #\vtab)。标量值小于256的字符也可以用八进制语法打印,该语法由前缀 #\
和三个八进制数字序列组成。 例如,#\000
等效于#\nul
。
Chez Scheme的fxvectors
和fixnum vectors
,跟vectors的打印方式类似,但使用前缀 #vfx(
代替 #
。 vector,bytevectors和fxvectors,可以打印有明确的长度前缀,并且当指定了明确的长度前缀时,可以省略重复的尾随元素。例如,可以将 #(a b c)
打印为 #3(a b c)
,将包含全零的长度为100的矢量打印为 #100(0)
。
Chez Scheme的box
对象,打印时带有#&
前缀,如#&17
是一个包含整数17的box。
record
以 #[type-name field ...]
的语法打印,这里的符号 type-name
是record
的名字,field ...
表示 record
里的字段内容。
共享和循环的结构可以使用图形标记和引用前缀 #n=
和 #n#
进行打印。 #n=
用于标记一个输入里的项, #n#
用于引用标记为n的项。例如,'(#1=(a) . #1#)
是一个pair,其 car 和 cdr 包含相同列表,#0=(a . #0#)
是一个循环列表,即它的 cdr 是它自己。
一个 $primitive
形式可像 quote
一样能缩写,使用前缀 #%
。例如,#%car
等价于 ($primitive 2 car)
, #3%car
等价于 ($primitive 3 car)
。
Chez Scheme 的“文件结束对象”可打印为 #!eof
。如果“文件结束对象”出现在正在加载的文件中的任意数据之外,就被看做是加载到文件末尾,并在这个点上停止加载。 因此,插入#!eof
到文件之中,可以方便追踪加载时的错误。
在弱对(点击查看详情)中的损坏指针表示为“broken weak pointer object”,打印为#!bwp
。
除了标准分隔符(空白,开闭圆括号,开闭方括号,双引号,分号和 #),Chez Scheme还将开括号,单引号,后引号和逗号视为分隔符。
在输入流中出现 #!r6rs
注释指令后,上述的Chez Scheme的词法扩展将被禁用,除非在之前出现 #!chezscheme
注释指令。每个通过 import
隐式加载的库,以及每个通过 --program
命令行选项的RNRS顶层程序或 load-program
程序,都被视为隐式以 #!r6rs
注释指令为开头。
根据修订版报告6的要求,符号和字符名称的大小写通常很重要。在相同的输入流里,#!fold-case
注释指令将名称设置为小写,就像被 string-foldcase
处理过一样,除非之前出现 #!no-fold-case
。没有出现任何指令时,且 参数 case-sensitive
被设置为 #f 时,名字也是小写的。
通过 write
, put-datum
, pretty-print
, 和 format ~s
选项,printer 总是用标准语法,对标准的修订报告6的对象进行打印。除非通过设置某个打印参数,来改变默认行为。例如,上述的Chez Scheme的扩展标识符语法的符号,printer 将使用的十六进制标量值转义序列来打印,除非 print-extended-identifiers
被设置为 true。同样地,printer 不会打印显式长度或省略尾部的重复元素,除非设置 参数print-vector-length
为 true。
第1.2节 符号约定
本书基本上遵循与The Scheme Programming Language 第4版 相同的符号约定。下面重申这些约定,并附带Chez Scheme特定的注释。
当说一个过程或句法形式产生的值是 未定义 时,该形式或过程或许返回任意数量的值,每个都可以是任意 Scheme 对象。只要返回结果是 未定义 ,Chez Scheme
通常返回唯一一个 void 对象(参见 void);但是,请避免参考这个对象,尤其是当你的程序要移植到另一个Scheme实现时。Chez Scheme 的 waiter (读-求值-打印循环,REPL) 会禁止打印空对象。
本书使用“必须”和“应该”此类词语来描述程序的条件,例如调用 vector-ref
的条件是提供一个小于vector长度的下标。如果使用“应该”一词,则意味着该条件由实现强制执行,即抛出一个异常,该异常通常是条件类型 &assertion
。如果使用了“应该”一词,那么异常可能会也可能不会被抛出。如果未抛出,该程序的行为是未定义的。短语“语法冲突”用于描述程序格式错误的情况。检测语法冲突先于程序执行。当检测到语法冲突时,会抛出 &syntax
类型异常,并停止执行。
显示在屏幕字体上的 Scheme 对象,就像是在键盘上键入的一样。这包括标识符,常量对象,括号 Scheme 表达式,和整个程序。斜体字体用于在句法形式的描述中衬托语法变量,在过程中描述中衬托参数。当一个技术用语首次出现时,也用斜体字来作衬。标识符的首字母通常不会大写,即使出现在句首也不会大写。这对写作斜体字的句法变量来说也是一样的。
在句法形式或过程的描述中,用模版来显示了句法形式或过程的应用。 语法关键字或过程名称以打字机字体给出,括号也是如此。语法或变量的其余部分以斜体显示,其使用的名称暗含了语法形式或过程所期望的表达式或变量的类型。省略号用于声明子表达式或参数出现零次或多次。
第1.3节 参数
Chez Scheme的所有系统定制都是通过参数来完成。一个参数是一个封装着内部状态变量的过程。当不带参数调用此过程时,它返回封装的变量值。如果它的参数不正确,则可能会引发异常,也可能会以某种方式过滤该参数。
运行在Chez Scheme的程序可能会创建和使用新的参数。使用参数而不是全局变量进行程序自定义有两个原因:首先,无意中重新定义一个自定义变量,会导致意外的问题,而无意中重新定义参数只会使参数不可访问。例如,在Chez Scheme的早期版本中,一个程序为了自己的目标而定义了 *print-level*
,对Scheme对象的打印产生了意想不到的影响。而为了自己目标而定义 print-level
,只会失去改变打印机行为的能力。当然,一个意外调用 print-level
的程序依然会以意想不到的方式影响系统,但这种情况不太可能发生,并且只能在不正确的程序中发生。
其次,当“赋值”完成时,参数的无效值可以立即检测并拒绝,而不是在第一次使用时,这时撤销和恢复旧值为时已晚。例如,将 *print-level*
赋值为 -1 ,该错误行为不会被捕获,直到第一次调用 write
或 pretty-print
时已为时已晚。而尝试将 -1 赋值给参数 print-level
,即 (print-level -1)
,在实际进行更改之前立即被标记为错误。
系统内置参数的介绍将贯穿本书的不同章节,并在本书背面的“表格摘要”中列出了其他语法格式和过程。在Chez Scheme的线程版本中,标记为“线程参数”的参数具有每个线程的值,而标记为“全局参数”的参数的值由所有线程共享。 Chez Scheme的非线程版本不区分线程参数和全局参数。有关创建和操作参数的更多信息,请参见 12.13节 和15.7节。
第1.4节 更多信息
下面列出的文章和技术报告记录了Chez Scheme的各种功能及其实现:
- 句法抽象 [14, 8, 17]
- 模块 [32]
- 库 [21]
- 储存管理[12, 13]
- 线程[10]
- 多返回值[2]
- 可选参数[16]
- 延续[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/。
网友评论