The Scheme Programming Language 读书笔记,chapter 8, 9.
Chapter 8. Syntactic Extension
语法扩展(syntactic extensions)也就是宏(macros)用于扩展程序的语法,消除重复模式。
语法扩展形式多为(keyword subform ...)
。语法扩展识别关键字,然后将其关联到具体的转换器(transformer)。定义语法扩展可以使用define-syntax
,let-sntax
以及letrec-syntax
。转换器可以使用syntax-rules
来创建,生成的转换器允许使用模式识别来扩展语法。转换器也可以是普通的执行诀,接受一个参数,然后执行某些计算。这种情况下,syntax-case
通常用于解构输入,syntax
通常用于构建输出。
identifier-syntax
以及make-variable-transformer
执行诀可以用来创建这样的转换器,它们接受单例标识符,并且支持向这些标识符赋值。前者允许简单的基于syntax-rules
的模式,后者允许任意计算。
语法扩展在求值的时候会被语法展开器展开成核心语法形式。展开的过程支持文法作用域。
本章描述的语法扩展机制属于"syntax-case"系统的一部分。一个可移植的实现在http://www.cs.indiana.edu/syntax-case/可以获取。
Section 8.1. Keyword Bindings
- 语法
(define-syntax keyword expr)
,其中expr的求值结果必须是一个转换器。 - 语法
(let-syntax ((keyword expr) ...) form1 form2 ...)
- 语法
(letrec-syntax ((keyword expr) ...) form1 form2 ...)
Section 8.2. Syntax-Rules Transformers
- 语法
(syntax-rules (literal ...) clause ...)
- 语法
_
- 语法
...
- 语法
(identifier-syntax (id1 tmpl1) ((set! id2 e2) tmpl2))
Section 8.3. Syntax-Case Transformers
syntax-case
是比syntax-rules
更通用的转换器定义语法,它甚至可以用来扭曲文法作用域。所有syntax-rules
都可以用syntax-case
来定义。
syntax-case
机制下,转换器是一个单参数的执行诀。这个参数叫做syntax boject
,用于表示待处理的形式。返回的值是一个语法对象,用于表示输出形式。
一个语法对象可以是下列任意形式:
-
一个类型非对子,串列,名号的值
-
一对语法对象
-
一串语法对象
-
一个wrapped对象
-
语法
(syntax-case expr (literal ...) clause ...)
-
语法
(syntax template)
-
语法
#'template
等价于上一条 -
执行诀:
(identifier? obj)
-
执行诀:
(free-identifier=? identifier1 identifier2)
-
执行诀:
(bound-identifier=? identifier1 identifier2)
-
语法
(with-syntax ((pattern expr) ...) body1 body2 ...)
-
语法
(quasisyntax template ...)
-
语法
#``template
-
语法
(unsyntax template ...)
-
语法
#,template
-
语法
(unsyntax-splicing template ...)
-
语法
#,@template
-
执行诀
(make-variable-transformer procedure)
-
执行诀
(syntax->datum obj)
-
执行诀
(datum->syntax template-identifier obj)
-
执行诀
(generate-temporaries list)
思考,所谓语法,就是将一些词赋予组织意义,用来黏合句子。
Section 8.4. Examples
略
Chapter 9. Records
如何定义record类型。
Section 9.1. Defining Records
define-record-type
用于创建record类型,例如:(define-record-type point (fields x y))
,会自动创建以下寒素:
(make-point x y)
(point? obj)
(point-x p)
(point-y p)
字段默认是不可改的,如果要将它们设为可改的,需要明确说明:
(define-record-type point (fields (mutable x) y))
然后就可以使用(point-x-set! p x)
来做修改。
相关语法:
(define-record-type record-name clause ...)
(define-record-type (record-name constructor pred) clause ...)
相关子句
(fields field-spec ...)
(parent parent-name)
(nongenerative)
(nongenerative uid)
(protocol expression)
(sealed #t)
(opaque #t)
(parent-rtd parent-rtd parent-rcd)
语法:
- fields
- mutable
- immutable
- parent
- protocol
- sealed
- opaque
- nongenerative
- parent-rtd
思考:语法,即在语义之前解析的一层规则
Section 9.2. Procedural Interface
(make-record-type-descriptor)
也可以用来创建新record类型。这个执行上的接口比语义上的接口更灵活,但是可能会降低可读性和有效性。
执行诀:
(make-record-type-descriptor name parent uid s? o? fields)
(record-type-descriptor? obj)
(make-record-constructor-descriptor rtd parent-rcd protocol)
(record-type-descriptor record-name)
(record-constructor rcd)
(record-predicate rtd)
(record-accessor rtd idx)
(record-mutator rtd idx)
Section 9.3. Inspection
如何从记录类型表述符获取信息。
相关执行诀:
(record-type-name rtd)
(record-type-parent rtd)
(record-type-uid rtd)
(record-type-generative? rtd)
(record-type-sealed? rtd)
(record-type-opaque? rtd)
(record-type-field-names rtd)
(record-field-mutable? rtd idx)
(record? obj)
(record-rtd record)
(本篇完)