標準 Scheme への追加機能に依存するプログラムは、その追加機能を名前で指定できることが望ましい。SRFI はこのような追加機能(フィーチャ)の仕様を与えるが、SRFI 0 では、使用する Scheme システムに特定のフィーチャが存在するかを cond-expand
により確認する方法を与える。フィーチャには次の 2 つの主要なクラスがあることが予想される。
(「読み取り構文」では、Scheme レポートに記載されている文法の解釈について言及する。)
前者のクラスに属するフィーチャにはほとんどの SRFI が含まれるであろう。 たとえば、リスト ライブラリSRFI 1 がその良い例である。 後者のクラスには、Unicode ソース コードのサポートや、標準とは異なる種類の括弧に関する内容が含まれる。
個々のフィーチャを利用するための管理方法は Scheme システムごとに異なるであろう。 特定のフィーチャが利用可能であるか利用不可能であるかは Scheme システムごとに異なるだろうし、利用する前に特定の処理を必要とするシステムもあるだろう (たとえば、コード中やプログラムの設定ファイルに "import" 句を書く方法、コマンド ライン オプションで指定する方法、モジュール定義における依存関係の宣言による方法、など) 。
さらに、プログラムの一部で特定のフィーチャを使用すると、そのフィーチャがプログラム全体で有効になるようなシステムもあるだろう。 また別のシステムでは、フィーチャのスコープを制御するためのもっと正確な機構があるだろう (たとえば、モジュール システムがサポートされている場合)。 一般的にいうと、フィーチャはプログラムの一部分では有効であり、また別の一部では無効であることが可能である。そのため、複数の SRFI が競合しているとしても、そのスコープが交わらなければ使用することが可能である。
SRFI 0 では、フィーチャを利用するための機構については規定しない。それはモジュール システムの役割であるべきだ、というのが我々の見解であるからだ。将来的には、モジュール システムに関する SRFI により SRFI 0 の意味が拡張されることを、我々は期待している。たとえば、フィーチャのスコープの規則の定義や、フィーチャ テストの一般化を行うことができるだろう。
ほとんどの Scheme システムは、追加機能を加えることで言語を拡張している (Unicode 文字や文字列を操作する機能や、バイナリ入出力、非同期割り込みなど) 。このような機能は、新しい手続きを定義したり、新しい構文を定義したり、標準手続きや標準特殊フォームの動作を拡張したりするなど、様々な方法で実現されている。ある機能はいくつかの、あるいは、ほとんどの Scheme システムに存在しているかもしれないが、その API は異なるだろう (手続きを使用するか特殊フォームを使用するか、名前、パラメータの個数、など)。異なる Scheme システムで実行可能なコードを書くためには、使用する Scheme システムで特定の機能が利用できるかどうかに応じて特定のコード範囲を有効または無効にするための、共通の構成要素があれば便利である。たとえば、この構成要素を使用して特定のバイナリ入出力機能が存在するか判定し、存在しなければ、ポータブルなライブラリをロードしてその手続きを実装することが可能である。
フィーチャは フィーチャ識別子 により識別される。 この構成要素の意味を明確に定義するためには、フィーチャ識別子は明確に定義された機能を示さなければならない。そのため、正当なフィーチャ識別子の意味する公式仕様を管理するための、この SRFI とは独立したレジストリが必要である。SRFI レジストリはこの目的のために使われる。フィーチャには最終的に、SRFI 編集者により意味のわかる名前 (エイリアス) が付けられることが望まれる。"srfi-N" というフィーチャ識別子を使うのではコードを読み書きするのが困難になるからだ。
別の問題として、この構成要素の束縛をいつ行うかという問題がある (つまり、この構成得要素が作用するのはいつか、ということ)。コンパイラが不要なコード範囲を削除してより良い静的解析を行えるように、束縛は早い時期に行われることが重要である。
この構成要素を、たとえば (feature-implemented? 'srfi-5)
のようにブール値を返す手続きとして実現する方法では、束縛時期が遅すぎるので、この目標は達し得ない (プログラムの実行時に判定することになる)。Common Lisp の #+
読み取りマクロのようなリアルタイム構成要素は非常に早い時期に作用するが、この方法では既存の Scheme システムのリーダに大きな変更を加える必要があり、また、その構文は特に人間に読みやすいものではない。これの代わりとして、マクロ展開時に作用する構成要素を使用する。
この構成要素は、実装を容易にするために、(プログラムの可読性と分かりやすさを保つように) この構成要素の使用に規制をかけるために、また、フィーチャのスコープに関する誤解を避けるために、プログラムのトップレベルにのみ使用できるように制限される。 この制限は、Scheme システムの特定の実装や、他の SRFI (特にモジュール システムに関する SRFI) によって解除してもよい。
<command or definition> --> <command> | <definition> | <syntax definition> | (begin <command or definition>+) | <conditional expansion form> <conditional expansion form> --> (cond-expand <cond-expand clause>+) | (cond-expand <cond-expand clause>* (else <command or definition>*)) <cond-expand clause> --> (<feature requirement> <command or definition>*) <feature requirement> --> <feature identifier> | (and <feature requirement>*) | (or <feature requirement>*) | (not <feature requirement>) <feature identifier> --> a symbol which is the name or alias of a SRFI
cond-expand
フォームは、フィーチャが存在するかどうかをマクロ展開時に検査する。このフォームは、上記の clause の 1 つの本体に展開されるか、構文処理時にエラーを起こす。
cond-expand
は、feature requirement が満たされている最初の clause の本体に展開を行う (else
clause が存在すれば、前の clause がどれも選択されなかった場合にそれが選択される)。
feature requirement は論理式として解釈する。
ここで <feature identifier>
は、
SRFI レジストリで示されているそのフィーチャ識別子に対応するフィーチャが
cond-expand
フォームの位置において有効であるときに真となり、
そうでなければ偽となる。この解釈によって論理式が真となるとき、
feature requirement は満たされていると考える。
使用例:
(cond-expand ((and srfi-1 srfi-10) (write 1)) ((or srfi-1 srfi-10) (write 2)) (else)) (cond-expand (command-line (define (program-name) (car (argv)))))
2 つめの例では、command-line
はコマンドライン引数にアクセスするためのフィーチャのエイリアスであると仮定している。このフィーチャが存在しなければ、マクロ展開時にエラーが起きる。
以下の SRFI 0 の最も簡単な実装では、すべての利用可能なフィーチャは組み込みであると仮定している (ここでは srfi-0
と srfi-5
が利用可能であると仮定している):
(define-syntax cond-expand (syntax-rules (and or not else srfi-0 srfi-5) ((cond-expand) (syntax-error "Unfulfilled cond-expand")) ((cond-expand (else body ...)) (begin body ...)) ((cond-expand ((and) body ...) more-clauses ...) (begin body ...)) ((cond-expand ((and req1 req2 ...) body ...) more-clauses ...) (cond-expand (req1 (cond-expand ((and req2 ...) body ...) more-clauses ...)) more-clauses ...)) ((cond-expand ((or) body ...) more-clauses ...) (cond-expand more-clauses ...)) ((cond-expand ((or req1 req2 ...) body ...) more-clauses ...) (cond-expand (req1 (begin body ...)) (else (cond-expand ((or req2 ...) body ...) more-clauses ...)))) ((cond-expand ((not req) body ...) more-clauses ...) (cond-expand (req (cond-expand more-clauses ...)) (else body ...))) ((cond-expand (srfi-0 body ...) more-clauses ...) (begin body ...)) ((cond-expand (srfi-5 body ...) more-clauses ...) (begin body ...)) ((cond-expand (feature-id body ...) more-clauses ...) (cond-expand more-clauses ...))))
この仕様では、cond-expand
フォームの clause がどれも満たされない場合はマクロ展開時にエラーが起きることを要求している。そのための標準的な方法がないので、この実装では syntax-error
フォームを使用し、このフォームが何らかの方法で実装されていることを仮定している。
This document and translations of it may be copied and furnished to others, and derivative works that comment on or otherwise explain it or assist in its implementation may be prepared, copied, published and distributed, in whole or in part, without restriction of any kind, provided that the above copyright notice and this paragraph are included on all such copies and derivative works. However, this document itself may not be modified in any way, such as by removing the copyright notice or references to the Scheme Request For Implementation process or editors, except as needed for the purpose of developing SRFIs in which case the procedures for copyrights defined in the SRFI process must be followed, or as required to translate it into languages other than English.
The limited permissions granted above are perpetual and will not be revoked by the authors or their successors or assigns.
This document and the information contained herein is provided on an "AS IS" basis and THE AUTHOR AND THE SRFI EDITORS DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.