R6RS:翻訳:R6RS:11.18 Binding constructs for syntactic keywords

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 を参照している。

More ...