This page is part of the web mail archives of SRFI 0 from before July 7th, 2015. The new archives for SRFI 0 contain all messages, not just those from before July 7th, 2015.
Hi Marc, we have reviewed the issues surrounding SRFI 0 resulting from the discussion so far. We've also studied a range of Scheme implementations for compatibility with the ideas of SRFI 0. The current draft covers a lot of the ground, but not all of it. In particular, some Scheme implementations take the stance that no features beyond R5RS are present "by default"; any additional features require explicit imports. It would be great if we could have a SRFI 0 which would cater to this situation, without impeding its viability on more traditional systems. This has turned out to be a complicated task; the mailing list discussion had already uncovered that there are non-trivial scoping issues to be worked out. Since the mailing list discussion has already shown most of the issues at hand, we decided to just go ahead and suggest a concrete revision of SRFI 0 which caters to these requirements. It is implementable with essentially the same machinery as the current SRFI 0 draft, but allows for a wider range of implementation strategies, and thus maps more naturally to the various native language extension mechanisms of current Scheme systems. Functionally, the revision suggestion subsumes the current draft. We hope you like it. Let us know! Dave, Mike, and Shriram (The SRFI Editors)Title: SRFI 0: Feature import and feature-based conditional expansion
It is desirable that program which depend on additions to standard Scheme name those additions. SRFIs provide the specifications of these additions ("features"), and SRFI 0 provides the means to actually check and handle their correct use. It is anticipated that there will be two classes of features:
("Reader syntax" refers to aspects of the syntax described by the grammars in the Scheme reports.)
The former class of features will probably include most SRFIs, exemplified by the list library specified in SRFI 1. The latter class includes Unicode and different kinds of parentheses.
One of the goals of this SRFI is to have feature implementations map naturally to the module systems of the respective Scheme implementations, where such a module system exists.
The scope of bindings for the provided features will vary over different implementations. Thus, to achieve portability, a program should only use a feature after an appropriate import clause, even if some Scheme implementations provide it by default.
SRFI 0, unlike other "require"-like library systems common in the Lisp world, separates between testing for the sheer existence of a feature and actually using it. This allows programs to be written which function in a wide variety of different Scheme implementations.
Most Scheme systems extend the language with some additional features (such as the ability to manipulate Unicode characters and strings, to do binary I/O, or to handle asynchronous interrupts). Such features may be provided in a variety of ways including new procedures, new program syntax, and extended behavior of standard procedures and special-forms. A particular functionality may exist in several or even most Scheme systems but its API may be different (use of a procedure or special-form, name, number of parameters, etc).
Different Scheme systems provide language extensions by different means: Some have them built-in by default, some provide them via on-demand loading of code, some provide them via module systems. Combinations of these approaches also exist.
To write code that will run on several Scheme systems, it is useful to have common constructs to:
Features are identified by feature identifiers. In order for the semantics of this construct to be well-defined, the feature identifier must of course refer to a feature which has a well-defined meaning. There is thus a need for a registry, independent of this SRFI, to keep track of the formal specification associated with each valid feature-identifier. The SRFI registry is used for this purpose.
Another issue is the binding time of this construct (i.e. the
moment when it operates). It is important that the binding time be
early so that a compiler can discard the sections of code that are not
needed, and perform better static analyses. Expressing this construct
through a procedure returning a boolean, such as
(feature-implemented? 'srfi-5)
, would not achieve this
goal, as its binding time is too late (i.e. program run-time). A
read-time construct, such as Common Lisp's #+
read-macro,
is very early but would require non-trivial changes to the reader of
existing Scheme systems and the syntax is not particularly
human-friendly. Instead, a macro-expansion-time construct is used.
It is desirable to separate the act of checking for the existence
of a feature from actually making it available for a Scheme program to
use. This enables program to make more involved decisions about what
features of the ones available it might use. Hence, the SRFI also
specifies an IMPORT-IMPLEMENTATION
form which makes the
bindings provided by a feature available. Separating this from the
conditional construct also makes for more readable programs,
especially in cases where the program requires a fixed set of
features, and the only decision it makes are is to determine if qthe
features exist (and the program will run) or not (in which case it
won't).
Macro-expansion time may not be early enough to handle features
which are effectively changes to the reader used by the Scheme
implementation. Therefore, a third construct,
IMPORT-READER-SYNTAX
, which may only occur at the
beginning of a syntactic processing unit, specifies its syntax.
COND-IMPLEMENTS
design One valid way to implement COND-IMPLEMENTS
is in
terms of a simpler IF-IMPLEMENTS
construct with
dependencies on just one feature at a time, and just one or two
branches. Why not specify IF-IMPLEMENTS
instead?
The COND-IMPLEMENTS
construct specified here gives
Scheme implementations more flexibility in implementing it. The
specification is intentionally ambiguous as to which clause will be
expanded in a COND-IMPLEMENTS
form. This is in order to
allow Scheme implementations to choose an especially convenient
(fastest/least memory-intensive/...) combination of implementations.
To demonstrate the utility of the conditional construct, consider the following example:
(cond-implements (srfi-a ... aaa ...) (srfi-b ... bbb ...))
where the programmer is implementing some abstraction that can use
function aaa
from SRFI a or can use function
bbb
from SRFI b. However, the semantic fit with
aaa
is substantially better, which the programmer
recognized by giving that implementation first. So if both SRFIs
exist, and the "quality" of implementation is the comparable for SRFI
a and SRFI b, then using the version with the better semantic fit
is probably more efficient. However if they both exist, but
SRFI a must be compiled and loaded from a slow reference
implementation, and SRFI b is implemented as a built-in
native-code library, it is preferable that the Scheme implementation
should use the second version.
<_expression_> --> (COND-IMPLEMENTS <cond-implements clause>+) <command or definition> --> (IMPORT-IMPLEMENTATION <feature identifier>+) <cond-implements clause> --> (<implementation requirement> <body>) --> (ELSE <body>) <implementation requirement> --> <feature identifier> --> (AND <implementation requirement>*) --> (OR <implementation requirement>*) --> (NOT <implementation requirement>) <feature identifier> --> srfi-<srfi number> <srfi number> --> <nonzero digit 10> <digit 10>* <nonzero digit 10> --> 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 <program> --> <syntax import>? <command or definition>* <syntax import> --> (IMPORT-READER-SYNTAX <feature identifier>+)
COND-IMPLEMENTS
COND-IMPLEMENTS
tests for the existence of feature implementations.
It either expands into the body of one of its clauses or signals an
error during syntactic processing. COND-IMPLEMENTS
expands into the
body of a clause whose implementation requirement the underlying
Scheme implementation can satisfy.
An implementation requirement has an obvious interpretation as a
logical formula, where the <feature identifier>
variables have meaning TRUE if an implementation corresponding to the
named feature exists in the underlying Scheme implementation, and
FALSE otherwise. An implementation requirement is satisfied if its
formula is true under this interpretation.
It is unspecified into which body the COND-IMPLEMENTS
form expands if
several clauses have satisfiable requirements.
The existence of an implementation in no way implies that the bindings provided by it are actually visible. (But it is possible that bindings provided by implementations are visible by default.)
IMPORT-IMPLEMENTATION
IMPORT-IMPLEMENTATION
makes available value and syntactic
bindings from feature implementations. If a feature specified in an
IMPORT-IMPLEMENTATION
clause does not exist, an error is
signalled during syntactic processing. If the bindings relating to a
feature implementation are already available,
IMPORT-IMPLEMENTATION
is a no-op. It is an error for the
bindings imported by one or several IMPORT-IMPLEMENTATION
forms to conflict with each other. The existence test here is the
same as in COND-IMPLEMENTS
.
IMPORT-IMPLEMENTATION
to appear
anywhere other than at toplevel.
IMPORT-READER-SYNTAX
In Scheme implementations which implement alternate reader syntaxes,
IMPORT-READER-SYNTAX
allows stating that a syntactic
processing unit is written in the syntax specified by a SRFI. If a
feature specified in an IMPORT-READER-SYNTAX
clause does
not have an implementation, an error is signalled during syntactic
processing. The alternative syntax will be in effect immediately
following the closing parenthesis of the
IMPORT-READER-SYNTAX
form. If the reader changes
relating to a feature implementation are already in effect,
IMPORT-READER-SYNTAX
is a no-op. It is an error for the
syntaxes imported by one or several IMPORT-READER-SYNTAX
forms to conflict with each other. The existence test here is the
same as in COND-IMPLEMENTS
.
It is an error for an IMPORT-READER-SYNTAX
to appear
anywhere but as the first form in a syntactic processing unit or
within that first form, either literally or as a result of macro
expansion.
This page is part of the web mail archives of SRFI 0 from before July 7th, 2015. The new archives for SRFI 0 contain all messages, not just those from before July 7th, 2015.
A feature implementation may be, for example:
The latter two possibilities allow loading or linking a feature implementation "on-demand" only for programs which actually use them. Some Scheme implementations might use the underlying package system to implement on-demand loading. Batch implementations might process a program using SRFI 0 to generate link commands. Other possibilities exist.
It is the intention that, if the implementation has a choice between equivalent "quality," it will choose the first matching clause in left-to-right order.
In Scheme implementations where feature implementations are loadable,
COND-IMPLEMENTS
by itself should
merely test for the existence of implementations, but not actually
load any code, import any bindings, or make any reader changes. The
actual loading/importing only happens through
IMPORT-IMPLEMENTATION
and
IMPORT-READER-SYNTAX
.
In Scheme implementations where feature implementations are not loadable,
COND-IMPLEMENTS
is a simple feature test, and
IMPORT-IMPLEMENTATION
and
IMPORT-READER-SYNTAX
are no-ops if they do not signal an
error.
The issue of alternative reader syntax is the most difficult. The
specification of IMPORT-READER-SYNTAX
makes the
assumption that one syntactic processing unit has a single syntax
throughout. It is convenient to have the processing unit specify
which syntax it is written in, rather than specifying the syntax
externally.
Since changing the reader syntax may have complex interactions with
macro expansion and other syntactic processing, the
IMPORT-READER-SYNTAX
must appear at the beginning of a
processing unit. The intention is that a Scheme implementation can
determine the syntax of a processing unit by retrieving the first form
in a unit via READ
and macro-expanding that form. This
makes the proposal compatible with Scheme implementations which depend
on reading in a whole processing unit before macro expansion.
A consequence of the specification is that an initial form specifying
a syntax change can really only use LET-SYNTAX
,
LETREC-SYNTAX
, uses of macros defined by them, and
COND-IMPLEMENTS
.
Scheme implementations that do not support changable readers need not
handle a COND-IMPLEMENTS
that appears as the first form specially.
Here, IMPORT-READER-SYNTAX
may be a simple macro.
The simplest implementation of SRFI 0 assumes that all existent features are built-in.
Nota bene: This implementation only demonstrates implementability under R5RS Scheme. It is by no means a reference implementation to be used in actual Scheme systems. Moreover, the behavior of this implementation is a significant restriction on the specification.
(define-syntax import-implementation (syntax-rules () ((import-implementation feature-id ...) (cond-implements (and feature-id ...) 42)))) (define-syntax import-reader-syntax (syntax-rules () ((import-reader-syntax feature-id ...) (cond-implements (and feature-id ...) 42))))
(The specification requires a macro-expansion time error to be signalled if a COND-IMPLEMENTS has no fulfilled clause. There is no standard way to so that, so this implementation uses the SYNTAX-ERROR form, with the assumption that an actual implementation would provide some way to do this.)
(define-syntax cond-implements (syntax-rules (and or not else srfi-0 srfi-5) ((cond-implements) (syntax-error "Unfulfilled COND-IMPLEMENTS")) ((cond-implements (else body ...)) (begin body ...)) ((cond-implements ((and) body ...) more-clauses ...) (begin body ...)) ((cond-implements ((and req1 req2 ...) body ...) more-clauses ...) (cond-implements (req1 (cond-implements ((and req2 ...) body ...) more-clauses ...)) more-clauses ...)) ((cond-implements ((or) body ...) more-clauses ...) (cond-implements more-clauses ...)) ((cond-implements ((or req1 req2 ...) body ...) more-clauses ...) (cond-implements (req1 (begin body ...)) (else (cond-implements ((or req2 ...) body ...) more-clauses ...)))) ((cond-implements ((not req) body ...) more-clauses ...) (cond-implements (req (cond-implements more-clauses ...)) (else body ...))) ((cond-implements (srfi-0 body ...) more-clauses ...) (begin body...)) ((cond-implements (srfi-5 body ...) more-clauses ...) (begin body...)) ((cond-implements (feature-id body ...) more-clauses ...) (cond-implements more-clauses ...))))
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.