The Racket Guide阅读笔记,chapter 16, 17.
16 Macros
本文描述Racket的宏。
另一个值得参考的是Fear of Macros。
Racket提供有宏调试器,以及syntax/parse库来帮助宏的写作。
16.1 Pattern-Based Macros
16.1.1 define-syntax-rule
(define-syntax-rule pattern template)
。
16.1.2 Lexical Scope
宏具有文法作用域。
16.1.3 define-syntax and syntax-rules
当然,也支持从scheme中继承而来的
(define-syntax id
(syntax-rules (literal-id ...)
[pattern template]
...))
16.1.4 Matching Sequences
输入rotate的例子:
(define-syntax rotate
(syntax-rules ()
[(rotate a c ...)
(shift-to (c ... a) (a c ...))]))
(define-syntax shift-to
(syntax-rules ()
[(shift-to (from0 from ...) (to0 to ...))
(let ([tmp from0])
(set! to from) ...
(set! to0 tmp))]))
16.1.5 Identifier Macros
前面定义的swap以及rotate,必须在括号里面使用。为了避免这个问题,需要使用标识符宏(identifier macro)。
(define-syntax val
(lambda (stx)
(syntax-case stx ()
[val (identifier? (syntax val)) (syntax (get-val))])))
(define-values (get-val put-val!)
(let ([private-val 0])
(values (lambda () private-val)
(lambda (v) (set! private-val v)))))
下面的执行变成可能:
> val
0
> (+ val 3)
3
> (val)
. val: bad syntax in: (val)
16.1.6 set! Transformers
可以直接用make-set!-transformer
来创建可更改的值。
16.1.7 Macro-Generating Macros
可以写一个宏(define-get/put-id val get-val put-val!)
来自动生成上面例子中所需的宏。
16.1.8 Extended Example: Call-by-Reference Functions
讲述使用define-cbr来定义一个call-by-reference函数。
16.2 General Macro Transformers
略
16.3 Module Instantiations and Visits
略
17 Creating Languages
上一章中的宏有以下限制:
- 宏无法在其上下文之内对语法进行限制,无法改变环绕其的形式
- 宏只会在文本意义上对语言进行扩展,最终还是要使用到语言的标识符,关键字以及字面值。
也就是说宏只在expander层面对语言进行扩展,却无法在reader层面对语言进行扩展。
17.1 Module Languages
模块的初始导入可以被称为模块语言。常见的如racekt以及racket/base。但是你可以自定义模块语言。通过使用all-from-out,except-out以及rename-out,可以修改既有的racekt从而产生racket的一个变体。
17.1.1 Implicit Form Bindings
有一些隐含模式必须包含在模块之内,比如#%app,#%datum,#%top等
> (module just-lambda racket
(provide lambda #%module-begin
; ten needs these, too:
#%app #%datum))
> (module ten 'just-lambda
((lambda (x) x) 10))
> (require 'ten)
17.1.2 Using #lang s-exp
在#lang
层面实现一个语言会更复杂一些。
#lang s-exp module-name
form ...
17.2 Reader Extensions
使用#reader形式可以在reader层级修改语言。
#reader ‹module-path› ‹reader-specific›
定义了下面的之后
; five.rkt
#lang racket/base
(provide read read-syntax)
(define (read in) (list (read-string 5 in)))
(define (read-syntax src in) (list (read-string 5 in)))
'(1 #reader"five.rkt"234567 8)
就变成了'(1 ("23456") 7 8)
。
'(1 #reader"five.rkt" 234567 8)
就变成了'(1 (" 2345") 67 8)
。
17.2.1 Source Locations
略
17.2.2 Readtables
略
17.3 Defining new #lang Languages
如何定义一个#lang language
。
language决定了剩下部分如何在reader层级解析。
其他略。
(本篇完)