9. 基本语法
在一个library形式或顶层程序的import形式的后面,构成库或顶层程序内部的形式依赖于被导入的库。尤其,被导入的句法关键词决定可用的句法抽象以及每个形式是一个定义还是一个表达式。可是,一些形式总是可用的,它们独立于被导入的库,包括常量字面量,变量引用,过程调用,和宏的使用。
9.1. 基本表达式类型(Primitive expression types)
本节的条目都是都是描述表达式,其可以出现在<expression>句法变量的地方。也可以参见第11.4小节。
常量字面量
<number> syntax
<boolean> syntax
<character> syntax
<string> syntax
<bytevector> syntax
一个由一个数字对象,或一个布尔,或一个字符,或一个字符串,或一个字节向量组成的表达式求值“等于它自己”。
145932 ⇒ 145932
#t ⇒ #t
"abc" ⇒ "abc"
#vu8(2 24 123) ⇒ #vu8(2 24 123)
就像5.10小节描述的那样,一个字面量表达式的值是不可改变的。
变量引用
<variable> syntax
由一个变量组成的表达式(5.2小节)是一个变量引用,如果它不是一个宏使用(见下面)的话。这个变量引用的值是被存储在这个变量绑定的位置的值。引用一个未绑定的变量是一个语法错误。
下面的例子假设基本库已经被导入:
(define x 28)
x ⇒ 28
过程调用
(<operator> <operand1> ...) 语法
一个过程调用由被调用的过程表达式,传递给这个过程的参数以及两边的下括号组成。在一个表达式上下文中,如果<operator>不是一个作为句法关键字绑定的标识符(见下面的9.2小节),那么这个形式是一个过程调用。
当一个过程调用被求值的时候,操作和操作数被(以一个未定义的顺序)求值,且最终产生的过程接受最终产生的参数。
下面的例子假设(rnrs base (6))库已被导入:
(+ 3 4) ⇒ 7
((if #f + *) 3 4) ⇒ 12
如果<operator>的值不是一个过程,那么一个条件类型是&assertion的异常被抛出。并且,如果一个过程接受的参数的数量不是<operand>的数量,那么一个条件类型是&assertion的异常被抛出。
注意: 相比于其它的Lisp方言,求值的顺序是未定义的,且操作表达式和操作数表达式总是以相同的求值规则被求值。
此外,尽管求值的顺序是未定义,但是对操作和操作数表达式进行的任何并发求值的结果必须与按某种顺序求值的结果一致。对每个过程调用的求值顺序可以有不同的选择。
注意:在许多Lisp方言中,空组合式()是合法的表达式。在Scheme中,写成表/点对形式的表达式至少要包含一个子表达式,因此()不是一个语法上有效的表达式。
9.2. 宏
库的顶层程序可以定义和使用新的叫做句法抽象(syntactic abstraction)或宏派生表达式和定义。一个句法抽象通过绑定一个关键词到一个宏转换(macro transformer),或简称为转换(transformer),来创建。转换决定一个宏的使用(被称为宏使用(macro use))怎样被转录我一个更加基本的形式。
大部分宏有形式:
(<keyword> <datum> ...)
其中<keyword>是唯一决定形式种类的标识符。这个标识符叫做宏的句法关键词(syntactic keyword),或简称为宏的关键词。<datum>的数量和每一个的语法由句法抽象决定。
宏使用可以表现为不正确的表形式,单独的标识符或set!形式,其中set!形式的第二个子形式是关键字(见第11.19小节,库的第12.3小节):
(<keyword> <datum> ... . <datum>)
<keyword>
(set! <keyword> <datum>)
在11.2.2和11.18小节描述的define-syntax, let-syntax 和letrec-syntax形式创建关键词的绑定,将它们与宏转换的形式联系起来,且控制它们可见的范作用域。
在11.19小节描述的syntax-rules 和identifier-syntax形式通过一个模式语言创建转换。并且,库的第12章描述的syntax-case形式允许通过任意的Scheme代码创建转换。
关键词和变量占据相同的名字空间。也就是,在相同的作用域内,一个标识符可以被绑定到一个变量或一个关键词中的零个或一个,不能同时绑定到两个,且任何一种本地绑定可以覆盖任何一种其它的绑定。
使用syntax-rules 和identifier-syntax定义的宏是“卫生的(hygienic)”和“引用透明的(referentially transparent)”,且因此保持了Scheme词法作用域的特点1819202122:
- 如果一个宏转换为一个没有出现在宏使用中的标识符(变量或关键词)插入一个绑定,就实际效果而言,该标识符在其整个作用域中将被改名使用,以避免与其他标识符冲突。
- 如果一个宏转换器插入了对某标识符的自由引用,那么,无论是否存在包围该宏的使用的局部绑定,该引用都将指向定义转换器时可见的绑定。
使用syntax-case工具定义的宏也是卫生的,除非datum->syntax(见库的第12.6小节)被使用。