R6RS:翻訳:R6RS:11.19 Macro transformers
11.19 マクロ変換器
[syntax (expand)] (syntax-rules (<literal> ...) <syntax rule> ...)
[auxiliary syntax (expand)] _
[auxiliary syntax (expand)] ...
構文: 各 <literal> は識別子でなければならない。各 <syntax rule> は次の形式でなければならない。
(<srpattern> <template>)
<srpattern> は限定つきの <pattern> で、以下の括弧でくくったよっつの形式のうちのひとつのなかで空でないもので、その最初の下位フォームが識別子ないしは下線 _ であるものである。 <pattern> は識別子、定数、以下の形式のいずれかである。
(<pattern> ...) (<pattern> <pattern> ... . <pattern>) (<pattern> ... <pattern> <ellipsis> <pattern> ...) (<pattern> ... <pattern> <ellipsis> <pattern> ... . <pattern>) #(<pattern> ...) #(<pattern> ... <pattern> <ellipsis> <pattern> ...)
<ellipsis> は識別子 "..." (みっつのピリオド)である。
<template> はパターン変数か、パターン変数でない識別子か、パターンデータか以下のいずれかである。
(<subtemplate> ...) (<subtemplate> ... . <template>) #(<subtemplate> ...)
<subtemplate> は <template> に 0 個以上の省略記号の続いたものである。
意味論: syntax-rules は、健全な書き換え規則を指定することにより、マクロ展開時に新しいマクロ展開器へと評価される。 syntax-rules で指定された展開器に関連づけられたキーワードのマクロが使用されると、いちばん左の <syntax-rule> から順に <syntax-rule> に含まれるパターンと照合がされる。照合するものが見つかるとマクロの使用はテンプレートに従って健全に転写される。照合するものが見つからない場合は構文違反である。
<pattern> 中に現れる識別子は、下線(_)、 リテラルリスト (<literal> ...) に挙げられた識別子、省略記号(...)である。これ以外の識別子で <pattern> 中に現れるものはパターン変数である。 (<literal> ...) 中に省略記号や下線が現れるのは構文違反である。
<srpattern> の最初の下位フォームは識別子であってもかまわないが、照合には関与せず、パターン変数ともリテラル識別子とも解釈されない。
パターン変数は任意の入力下位フォームと一致し、入力の要素を参照するのに使われる。 <pattern> 中に同一のパターン変数が現れるのは構文違反である。
下線も任意の入力下位フォームに一致するが、パターン変数ではないため、入力の要素を参照するのに使うことはできない。また、複数の下線が <pattern> 中に現れることもできる。
リテラル識別子が一致するのは、入力下位フォームが識別子で、その入力式での出現とリテラルリストでの出現の両方が同一の字句束縛であるか、どちらの識別子も同一の名前で、字句束縛を持たない場合である。
省略記号の続く部分パターンは入力の 0 個以上の要素に一致する。
より形式的に言うと、入力フォーム F がパターン P に一致するのは以下の条件のひとつを見たす場合かつその場合に限られる。
- P が下線(_)である場合
- P がバターン変数である場合
- P がリテラル識別子であり、マクロの出力に挿入される識別子以外で P と F が両方ともマクロ出力に現れたとき、 F が P と同一の束縛を参照している場合(ふたつの名前風の識別子がどちらも何の束縛も参照しないない場合、すなわち、どちらも未定義である場合も、両方とも同じ束縛を参照しているものと考える)。
- P が (P1 ... Pn) の形式でF が n 要素のリストで P1 から Pn に一致する場合
- P が (P1 ... Pn . Px) の形式で F が n 要素以上のリストないしは非真正リストで、最初の n 要素が P1 から Pn に一致し、 n 番目の cdr が Px に一致する場合。
- P が (P1 ... Pk Pe <ellipsis> Pm+1 ... Pn) の形式で、 <ellipsis> が識別子 ... で、かつ F が n 要素のリストで、最初の k 要素が P1 から Pk に一致し、 次の m - k 要素が Pe に一致し、残りの n - m 要素が Pm+1 から Pn に一致する場合。
- P が (P1 ... Pk Pe <ellipsis> Pm+1 ... Pn . Px) の形式で、 <ellipsis> が識別子 ... で、かつ F が n 要素のリストないしは非真正リストで、最初の k 要素が P1 から Pk に一致し、 次の m - k 要素が Pe に一致し、残りの n - m 要素が Pm+1 から Pn に一致し、最後の n 番目の cdr が Px に一致する場合
- P が #(P1 ... Pn) の形式で F が P1 から Pn に一致する n 個の要素のベクタである場合
- P が #(P1 ... Pk Pe <ellipsis> Pm+1 ... Pn) の形式で、 <ellipsis> が識別子 ... で、かつ F が n要素以上のベクタで、その最初の k 要素が P1 から Pk に一致し、次の m - k 要素がそれぞれ Pe に一致し、残りの n - m 要素が Pm+1 から Pn に一致する場合
- P がパターンデータ(リスト、ベクタ、シンボル以外のデータ)であり、 F が equal? 手続きの意味で等しい場合
マクロの使用が一致した <syntax rule> テンプレートにしたがって転写されるとき、テンプレート中に現れたパターン変数は入力中で一致した部分フォームに置き換えられる。
パターン変数や省略記号でないパターンデータや識別子は出力にコピーされる。省略記号の続いた部分テンプレートは 0 個以上の部分テンプレートの出現に展開される。部分パターン中のパターン変数でひとつ以上の省略記号の続いたものは、部分テンプレート中では(最低限)同じ個数の省略記号の続いたかたちで現れる。これらのパターン変数は、指定された通りに分散して入力部分フォーム中で束縛されたものに出力中に置き換えらる。部分テンプレート中で、部分パターンで対応したものより多くパターン変数に省略記号が続いた場合、必要に応じて入力フォームが複製される。部分テンプレートには最低限ひとつ、部分パターンで省略記号の続いたものを含まねばならず、また、少なくともひとつ、そのようなパターン変数について、部分テンプレートにはパターン変数の現れた部分パターンと同じ個数だけ省略記号が現れなければならない(さもなくは、部分フォームを出力中で何度繰り返せばよいのかを展開器が決定できない)。この段落で述べた制約が満たされない場合、それは構文違反となる。
(<ellipsis> <template>) 形式のテンプレートは、テンプレート中の省略記号が特別な意味を持たない以外、 <template> と等価である。したがった、 <template> 中に含まれる省略記号は単にふつうの識別子として扱われる。特に、 (... ...) というテンプレートはひとつの省略記号 ... になる。これによって、省略記号を含むフォームに展開される構文抽象を書くことができるようになる。
(define-syntax be-like-begin (syntax-rules () ((be-like-begin name) (define-syntax name (syntax-rules () ((name expr (... ...)) (begin expr (... ...)))))))) (be-like-begin sequence) (sequence 1 2 3 4) ⇒ 4
補助識別子の健全な使用例として、 let と cond が Appendix B の 11.16 節のように定義されていた場合、これらは(要求通り)健全に働き、以下のようなものもエラーにならない。
(let ((=> #f)) (cond (#t => ’ok))) ⇒ ok
cond のマクロ変換器は => を局所変数、すなわち式として認識し、マクロ展開器が構文キーワードとして扱う識別子 => としては認識しない。そのため、この例は次のように展開され、
(let ((=> #f)) (if #t (begin => ’ok)))
表明違反になる
(let ((=> #f)) (let ((temp #t)) (if temp (’ok temp))))
にはならない。
[syntax (expand)] (identifier-syntax <template>)
[syntax (expand)] (identifier-syntax (<id1> <template1>) ((set! <id2> <pattern>) <template2>))
[auxiliary syntax (expand)] set!
構文: <id> は識別子でなければならず、 <template> は syntax-rules と同様でなければならない。 Syntax: The <id>s must be identifiers. The <template>s must be as for syntax-rules.
意味論: identifier-syntax の最初の形式で生成された変換器がキーワードに束縛されると、スコープ中でのキーワードへの参照は <template> で置き換えられる。
(define p (cons 4 5)) (define-syntax p.car (identifier-syntax (car p))) p.car ⇒ 4 (set! p.car 15) ⇒ &syntax exception
次に、より一般的に、identifier-syntax 形式では set! の使われた場合に起こることを決定することができる。この場合、識別子自身の使用くは <template1> で置き換えられ、識別子とともに set! を使った場合は <template2> に置き換えられる。
(define p (cons 4 5)) (define-syntax p.car (identifier-syntax (_ (car p)) ((set! _ e) (set-car! p e)))) (set! p.car 15) p.car ⇒ 15 p ⇒ (15 . 5)