R6RS:翻訳:R6RS:11.18 Binding constructs for syntactic keywords
11.18 構文キーワードの束縛構文
let-syntax と letrec-syntax フォームはキーワードを束縛する。 begin フォームと同様に、 let-syntax や letrec-syntax フォームは定義の文脈に現れることができ、その場合定義として扱われ、本体部分の中のフォームは定義でなければならない。 let-syntax や letrec-syntax は式の文脈にも現れることができ、その場合は本体部分中のふぉーむは式でなければならない。
[syntax] (let-syntax <bindings> <form> ...)
構文: <bindings は次の形式をしていなければならない。
((<keyword> <expression>) ...)
各 <keyword> は識別子であり、各 <expression> は、マクロ展開時に、変換器に評価される式である。変換器は syntax-rules や identifier-syntax (R6RS:翻訳:R6RS:11.19 Macro transformers 参照)や R6RS:翻訳:Standard Libraries:12 syntax-case で述べられている他の仕組みのひとつで作成される。 <keyword> が束縛されるキーワードのリストの中に 2 回以上現れるのは構文違反である。
意味論: <form> は、キーワードが <keyword> であるマクロで、指定された変換器に束縛されたマクロで let-syntax の構文環境を拡張した構文環境で展開される。 <keyword> の各束縛は <form> をその領域とする。
let-syntax フォームの <form> は、定義の文脈でも式の文脈でも、暗黙の begin で囲まれているように扱われる。 R6RS:翻訳:R6RS:11.4.7 Sequencing 参照。したがって、 <form> を展開した結果の定義群は let-syntax が持つであろう領域の代わりに現れた定義と同一の領域を持つ。
実装系の義務: <expression> の値が変換器でないことを検知すべきである。
(let-syntax ((when (syntax-rules ()
((when test stmt1 stmt2 ...)
(if test
(begin stmt1
stmt2 ...))))))
(let ((if #t))
(when if (set! if ’now))
if)) ⇒ now
(let ((x ’outer))
(let-syntax ((m (syntax-rules () ((m) x))))
(let ((x ’inner))
(m)))) ⇒ outer
(let ()
(let-syntax
((def (syntax-rules ()
((def stuff ...) (define stuff ...)))))
(def foo 42))
foo) ⇒ 42
(let ()
(let-syntax ())
5) ⇒ 5
[syntax] (letrec-syntax <bindings> <form> ...)
構文: let-syntax と同一である。
意味論: <form> は、キーワードが <keyword> であり、指定された変換器に束縛されたマクロで letrec-syntax の構文を拡張した構文環境で展開される。各 <keyword> の束縛は <form> と同様に <bindings> もその領域とする、そのため、変換器は letrec-syntax フォームで導入されたマクロの使用に展開することができる。
letrec-syntax フォームの <form> は、定義の文脈でも式の文脈でも、暗黙の begin で囲まれているように扱われる。 R6RS:翻訳:R6RS:11.4.7 Sequencing 参照。したがって、 <form> を展開した結果の定義群は letrec-syntax が持つであろう領域の代わりに現れた定義と同一の領域を持つ。
実装系の義務: 実装系は <expression> の値が変換器でないことを検知するべきである。
(letrec-syntax
((my-or (syntax-rules ()
((my-or) #f)
((my-or e) e)
((my-or e1 e2 ...)
(let ((temp e1))
(if temp
temp
(my-or e2 ...)))))))
(let ((x #f)
(y 7)
(temp 8)
(let odd?)
(if even?))
(my-or x
(let temp)
(if y)
y))) ⇒ 7
次の例は let-syntax と letrec-syntax がどのように異なるかを活写している。
(let ((f (lambda (x) (+ x 1))))
(let-syntax ((f (syntax-rules ()
((f x) x)))
(g (syntax-rules ()
((g x) (f x)))))
(list (f 1) (g 1))))
⇒ (1 2)
(let ((f (lambda (x) (+ x 1))))
(letrec-syntax ((f (syntax-rules ()
((f x) x)))
(g (syntax-rules ()
((g x) (f x)))))
(list (f 1) (g 1))))
⇒ (1 1)
ふたつの式は最初の式の let-syntax フォームがふたつめでは letrec-syntax になっている以外同一である。最初の式では g 中に現れる f は let で束縛された変数を参照しているのに対して、ふたつめでは letrec-syntax フォームで束縛の確立されたキーワード f を参照している。