R6RS:翻訳:R6RS:7.2 Import and export levels

R6RS:翻訳:R6RS:7.2 Import and export levels

7.2 インポート・エクスポートレベル

ライブラリを展開するためには他のライブラリの実行時情報が必要になることがある。例えば、マクロ変換子がライブラリ A の手続きを呼んでいる場合、ライブラリ B でマクロが使用されるよりも前にライブラリ A はインスタンス化されていなければならない。ライブラリ A はライブラリ B が最終的にプログラムの一部として実行されるときには必要ないかもしれないし、ライブラリ B の実行時にも必要であるかもしれない。ライブラリシステムではれらをフェーズを使って区別する。本節ではフェーズについて説明する。

各ライブラリは展開時情報(最低でも、インポートしているライブラリ、エクスポートするキーワード、エクスポートする変数、変換子式を評価するためのコード)と実行時情報(最低でも、変数定義の右辺式を評価するためのコード、本体式を評価するためのコード)で特徴づけることができる。展開時情報はエクスポートしている束縛への参照を展開するために利用可能でなければならず、実行時情報はエクスポートしている変数の束縛を評価するために利用可能でなければならない。

フェーズはライブラリ内の式が評価されるタイミングを言う。ライブラリの本体では、トップレベル式と define の右辺が実行時、すなわちフェーズ 0 で評価され、 define-syntax の右辺は展開時、すなわちフェーズ 1 で評価される。 define-syntax、 let-syntax、 letrec-syntax がフェーズ n で評価されるコード内に現れた場合、その右辺はフェーズ n + 1 で評価される。

これらのフェーズはライブラリ自体の使われるフェーズに対して相対的である。ライブラリのインスタンスは、別のライブラリに相対的な特定のフェーズにおいて変数宣言や式を評価すること(これをインスタンス化と呼ぶ)に相当する。例えば、ライブラリ B のトップレベル式が別のライブラリ A のエクスポートしている変数を参照しているとき、ライブラリ B はライブラリ A のフェーズ 0 (このフェーズは B のフェーズに対して相対的である)におけるインスタンスのエクスポートを参照する。ここで、 B 内のフェーズ 1 の式が A の同一の束縛を参照している場合、(B のフェーズと相対して)フェーズ 1 における A のインスタンスのエクスポートを参照することになる。

ライブラリの訪問(visit)は、別のライブラリに相対的な特定のフェーズにおいて構文の宣言を評価すること(これを訪問 -- visiting と呼ぶ)に相当する。例えば、ライブラリ B 内のトップレベル式が別のライブラリ A のエクスポートするマクロを参照している場合、ライブラリ B は(B のフェーズと相対して) A のフェーズ 0 における訪問のエクスポートを参照する。これは、マクロ変換子の式をフェーズ 1 で評価することに相当する。

レベルは、ある識別子がどのフェーズで参照されるかを決定する字句上の属性である。ライブラリ内の定義によって束縛される各識別子のレベルは 0 である。すなわち、識別子は定義したライブラリ内ではフェーズ 0 でのみ参照することができる。インポートされた各束縛のレベルは、そのライブラリをインポートするライブラリの import の for フォームと、識別子をエクスポートしているライブラリにおけるその識別子のレベルを使って決定される。インポートレベルとエクスポートレベルのそれぞれのレベルすべての組み合わせを求め、その組を足し算したものを使う。例えば、レベル p_ap_b でエクスポートされた識別子を、レベル q_aq_bq_c でインポートした場合、その識別子への参照は p_a + q_ap_a + q_bp_a + q_cp_b + q_ap_b + q_bp_b + q_c で有効になる。 <import set> に for を指定しなかったものは (for <import set> run) と等価であり、これは (for <import set> (meta 0)) に等しい。

エクスポート元のライブラリ内で定義された束縛のエクスポートレベルは 0 である。再エクスポートされた束縛、すなわち、別のライブラリからインポートされたものをエクスポートした束縛のエクスポートレベルは、その束縛を再エクスポートするライブラリ内で有効なインポートレベルと同じである。

ライブラリ報告書で定義されているライブラリについては、ほぼすべての束縛はレベルは 0 エクスポートされる。例外は (rnrs base (6)) ライブラリの syntax-rules、 identifier-syntax、 ...、 _ で、これらはレベル 1 でエクスポートされている。また、 (rnrs base (6)) ライブラリの set! は レベル 1 でエクスポートされてい、さらに (rnrs (6)) 複合ライブラリ(R6RS:翻訳:Standard Libraries:15 Composite library参照)の束縛はすべて、レベル 0 と 1 でエクスポートされている。

ライブラリ内のマクロ展開により、そのライブラリで直接インポートしなかった識別子への参照が導入されることがある。この場合、その参照に対するフェーズは、もとのライブラリ(すなわち、その識別子の字句文脈を提供するライブラリ)のフェーズとその参照を取り囲むライブラリのフェーズの差分だけシフトしたレベルと一致しなければならない。例えば、あるマクロ変換子を起動するライブラリを展開していて、マクロ変換子の評価で別のライブラリでエクスポートされている識別子を参照しているとし(このとき、このライブラリのフェーズ 1 のインスタンスが使われる)、さらに、その束縛の値はレベル n の識別子のみを表す構文オブジェクトであるとする。このとき、展開されるライブラリではその識別子はフェーズ n + 1 だけで使われるものでなければならない。このようにレベルとフェーズが組み合わせられることにより、ライブラリは非負のフェーズにしか存在しないにもかかわらず、識別子に負のレベルを与えることが有用になるのである。

ライブラリの任意の定義がプログラムの展開形においてフェーズ 0 で参照されるとき、参照されるライブラリのインスタンスは、プログラム中の定義や式が評価される前にフェーズ 0 で作成される。この規則は推移的に適用される。あるライブラリの展開形がフェーズ 0 で別のライブラリの識別子を参照するとき、識別子を参照するライブラリがフェーズ n でインスタンス化される前に、参照されるライブラリの側はフェーズ n でインスタンス化されていなければならない。参照側のライブラリが 0 以上の任意のフェーズ n でインスタンス化されるとき、逆に、定義側のライブラリは、その参照が評価される前の不特定のタイミングで、フェーズ n でインスタンス化される。同様にマクロキーワードがライブラリの展開中にフェーズ n で参照された場合、それを定義するライブラリは、その参照が評価される前の不特定のタイミングで、フェーズ n で訪問される。

実装系は異なるフェーズのインスタンスないし訪問を区別してもよいし、任意のフェーズにおけるインスタンスないし訪問を他の任意のフェーズのインスタンスないし訪問として使ってもよい。さらに、実装系は任意のフェーズにおけるライブラリ群の別個の訪問と 0 以上のフェーズにおけるライブラリ群のインスタンスを、同時に、またはどちらかを使って各 library を展開してもよい。実装系は参照を満足するために必要なフェーズ数よりも多くのライブラリのインスタンスないし訪問を作成してもよい。ある識別子のレベルと整合しないフェーズで、その識別子が式として現れた場合、実装系は展開時ないしは実行時に例外を発生させてもよいし、その参照を認めてもよい。したがって、ライブラリのインスタンスが各フェーズ間、 library 展開間で区別されるのか共有されるのかに依存した意味を持つライブラリは可搬でないことがある。

More ...