10. 扩展过程
宏使用(见第9.2小节)在求值开始的时候(在编译或解释之前)通过语法扩展器(expander)被扩展为核心形式。核心形式的集合石实现定义的,在扩展器输出中这些形式的表示也是。如果扩展器遇到一个句法抽象,那么他会调用相关的转换器去扩展句法抽象,然后对转换器(transformer)返回的形式重复扩展过程。如果扩展器遇到一个核心形式,它会递归地处理表达式或定义上下文中它的子形式,如果有的话,且从被扩展的子形式中重建形式。关于标识符绑定的信息在为变量和关键词实施词法作用域扩展的时候被维持。
为了处理定义,扩展器从左向右地处理<body>(见11.3小节)或<library body>(见7.1小节)中的初始形式。扩展器怎样处理每个遇到的形式取决于形式的种类。
- 宏使用
- 扩展器调用相关的转换器来转换宏使用,然后对产生的形式递归地执行适当的操作。
define-syntax形式- 扩展器扩展和求值右边的表达式,且绑定关键词到最终的转换器。
define形式- 扩展器记录这样的事实直到所有的定义都被处理,被定义的标识符是一个变量,而不是右边表达式的推迟扩展。
begin形式- 扩展器将子形式拼接到它正在处理的内部形式的表中。(见11.4.7小节)
let-syntax或letrec-syntax形成- 扩展器将里面的内部形式拼接到它正在处理的(外面的)内部形式的表中,使得通过
let-syntax和letrec-syntax绑定的关键词只在里面的内部形式可见。 - 表达式,也就是,非定义
- 扩展器完成推迟的右边表达式和内部当前的即遗留的表达式的扩展,且然后从被定义的变量,被扩展的右边的表达式,和被扩展的内部表达式创建等价于
letrec*的形式。
对于一个变量定义的右边,扩展被推迟到所以的定义可见之后。因此,如果可以的话,右边的每个关键词和变量引用都解析到本地绑定。
在形式序列中的一个定义必须不能定义任意下列的标识符,其绑定被用作判断定义或形式序列中任何在其之前的定义的含义。比如,下列表达式的内部违反了这个限制:
(let ()
(define define 17)
(list define))
(let-syntax ([def0 (syntax-rules ()
[(_ x) (define x 0)])])
(let ([z 3])
(def0 z)
(define def0 list)
(list z)))
(let ()
(define-syntax foo
(lambda (e)
(+ 1 2)))
(define + 2)
(foo))
下面的没有违反这个限制:
(let ([x 5])
(define lambda list)
(lambda x x)) ⇒ (5 5)
(let-syntax ([def0 (syntax-rules ()
[(_ x) (define x 0)])])
(let ([z 3])
(define def0 list)
(def0 z)
(list z))) ⇒ (3)
(let ()
(define-syntax foo
(lambda (e)
(let ([+ -]) (+ 1 2))))
(define + 2)
(foo)) ⇒ -1
实现应当将违反限制当作语法错误对待。
注意这个算法不直接地再处理任何形式。它要求整个定义中一个单独的从左到右的途径,其后是表达式和推迟的右手边里的一个单独的途径(任何顺序)。
例如:
(lambda (x)
(define-syntax defun
(syntax-rules ()
[(_ x a e) (define x (lambda a e))]))
(defun even? (n) (or (= n 0) (odd? (- n 1))))
(define-syntax odd?
(syntax-rules () [(_ n) (not (even? n))]))
(odd? (if (odd? x) (* x x) x)))
在这个例子中,第一次遇到defun的定义,且关键词defun与转换器相关,转换器从扩展和对应的右手边的求值得来。defun的一个使用在接下来被遇到,且扩展到一个define形式中。这个定义形式右手边的扩展是推迟的。odd?的定义是下一个且是与其相关的关键词odd?的结果,其转换器从对应的右手边的扩展和求值得来。odd?的一个使用出现在旁边,且被扩展;作为结果的对not的调用被认为是一个表达式,这是因为not作为一个变量被绑定。此时,扩展器完成当前表达式(not的调用)和被推迟的even?定义右侧的扩展;出现在这些表达式中的odd?的使用通过使用与odd?关联的转换器扩展。最终的输出等价于:
(lambda (x)
(letrec* ([even?
(lambda (n)
(or (= n 0)
(not (even? (- n 1)))))])
(not (even? (if (not (even? x)) (* x x) x)))))
尽管输出的结构是实现定义的。
因为定义被表达式在一个<top-level body>中可以交错地出现(见第8章),所以<top-level body>扩展器的处理有时更加复杂。它的行为想上面描述的<body>或<library body>以及以下例外:当扩展器发现一个非定义,它推迟其扩展并继续扫描定义。一旦它到达形式集合 的结尾,那么它处理推迟的右手边和内部表达式,然后从被定义的变量中生成等价于letrec*的形式,扩展右手边表达式,且扩展内部表达式。对于每一个出现在内部变量定义之前的内部表达式<expression>,在对应的地方一个哑绑定被创建以letrec*绑定的集合的形式,其左边是一个新鲜的临时变量,右边等价于(begin <expression> <unspecified>),其中<unspecified>是没有副作用的,所以从左到右的求值顺序被保留。begin的包装使得<expression>可以求值得到任意数量的值。