R7RS SRFI implementations
Our intention is to bridge gaps between credible Scheme platforms, as well as explore what is possible to implement sanely in R7RS. Unlike a lot of legacy "portable" Scheme code, this is not a freak show. Therefore:
Feel free to assume sane platform properties like a full numeric tower (excluding exact complex numbers), Unicode, etc. and keep
cond-expandusage to a minimum. (Moving to an R7RS-large base will make this point moot.)
Feel free to use other SRFIs in your SRFI implementation, even if they're not in this repository, if the alternative is using horrid hacks.
Feel free to use R6RS libraries in your SRFI implementation (imported via the R7RS library system), if the alternative is using horrid hacks. In particular, the Larceny project hosts a number of R7RS libraries named
(r6rs *), under
tools/R6RS/in its source tree, which implement the APIs of the corresponding
(rnrs *)libraries of R6RS; feel free to use those.
Test suites are written in a strict format using SRFI-64 for human and machine consumption; see below.
For those SRFIs which cannot be implemented in pure R7RS, it's fine to write libraries that just wrap features of specific platforms via
cond-expandand thus at least work across several platforms even if not all R7RS implementations. However, don't try to implement functionality via library code when it's clearly intended to be implemented at the platform level.
Withdrawn SRFIs are no priority since we assume they've been withdrawn for good reasons, but if there's any which you find useful then feel free to make a request or (better) contribute it.
Please use the standard SRFI license, found at the bottom of most SRFI pages.
As explained above, we expect some basic maturity and feature richness from platforms. So far this is not documented in any more detail, but it should be something along the lines of:
If a library in this repository doesn't work on your preferred Scheme platform, file a bug report. If it contains a working patch it will most likely be accepted; otherwise it might get rejected on the grounds that the mentioned Scheme platform is not suitable.
The author of this repository uses Chibi to test the libraries. See the next section for instructions.
Other than Chibi, the following platforms are explicitly intended to be supported once they implement R7RS:
The following do not intend to support R7RS, for various reasons:
- MIT/GNU Scheme
Using Chibi to test the implementations
Chibi Scheme is a clean, small, portable, and pretty much fully R7RS compliant Scheme platform, so it's a good choice for testing R7RS libraries.
- Clone Chibi from its git repository and build it by running
- Create the directory
lib/needed-for-initin the source tree.
- Copy the directory
- Remove all files and directories except
Run Chibi as follows:
LD_LIBRARY_PATH=$chibi_repo \ CHIBI_MODULE_PATH=$chibi_repo/lib \ $chibi_repo/chibi-scheme \ -I $srfi_repo \ -I $chibi_repo/lib/needed-for-init \ remaining arguments ...
All implementations should be valid R7RS-small libraries for now. We will move to an R7RS-large core/base when possible.
Libraries go into a file named
nis the SRFI number. The library is correspondingly named
Test suites are libraries too, and go into
srfi-testsdirectory, and are named accordingly. They must export a procedure named
(srfi-tests aux). The first argument to this macro must be the identifier
run-tests, and the second must be the string
"SRFI-n"for every SRFI-
n. The rest of the arguments make up the body of an SRFI-64 test suite; the initial
test-endforms must not appear in this body, since
The following rules about libraries apply to all libraries in this project, including SRFI implementations and test suites.
The order of things in a library declaration is:
- auxiliary code in a
beginif the main body is in an
- the main body as an
If an export or import list doesn't fit in one line, then put a newline directly after the
importkeyword, i.e., don't put any export or import specs on the same line as the keyword.
When there are many exports, put the closing parenthesis of the export form on its own line. Don't do this for imports.
If there is a substantial amount of code such that the indentation of the library form is an annoyance, split the main body of the library into a file named
When using a reference implementation with a substantial amount of code, put the original source code in a file
n.upstream.scm, and do not edit that file.
includedirectly that if no changes are needed; otherwise copy it to
n.body.scmand make changes there. This is because some reference implementations change ad-hoc without version control; we want to know what version we forked.
Follow Riastradh's Lisp Style Rules for new code: http://mumble.net/~campbell/scheme/style.txt
Using reference implementations
You can probably often just wrap a reference implementation in an R7RS library, but do modify them to make good use of R7RS features, to avoid dirty hacky things like redefining type predicates (it's mostly illegal anyway now), liberal use of global variables (use parameters instead), etc.
Be careful about the copyright and licensing. When putting source code in an
n.upstream.scmfile, add suitable legal boilerplate even if the original code didn't have any (usually the SRFI HTML page will have a copyright). The same boilerplate goes into
For some SRFIs, setting the
debug-mode parameter from the library
(srfi aux) to true while loading the library will enable improved
diagnostics, usually at the expense of performance. Note that there
is no portable and declarative way to do this; it relies on the
platform supporting an imperative and sequential method for loading
modules and executing code in-between. It is most likely to work in a
REPL, if at all. A library might also be loaded only a single time
for the whole run-time of a platform, so a restart might be necessary
to load a library with a different
debug-mode setting. A number of
SRFIs also support other settings through the
(srfi aux) library;
the same limitations apply to those.
and-let*: The author of this SRFI thought that
let*is supposed to error when the same identifier is bound multiple times in sequential clauses, and specified
and-let*to do the same; it was in fact an ambiguity prior to R6RS what
let*should do, and has been clarified since R6RS that it should allow sequential repeated bindings. Racket's, Guile's, and Chibi's SRFI-2 implementations do allow it, and it's a lot easier to implement too, hence our implementation allows it as well.
The SRFI proposes an R6RS library
(streams) with sub-libraries
(streams primitive) and
(streams derived). We provide these as
(srfi 41 primitive), and
(srfi 41 derived),
All identifiers have been lowercased. If you have source code using
identifiers with uppercase letters, you might want to use the
test-runner-simple: In line with the specification (and contrary to the reference implementation), this returns a runner that does no logging and does not use its "aux value" field.
However, when you don't install any test runner explicitly before starting your test suite, a modified simple test runner is installed which does logging.
test-read-eval-string: This now takes an optional
envargument to specify in what environment to evaluate. Passing
#fwill explicitly attempt to call
evalwith a single argument, which is an error in R7RS. Leaving the argument out will try to use a sane platform-specific default but falls back to
test-exit: A non-standard extension: exits with a non-zero exit status if any tests failed or unexpectedly passed.
The "u8vector" API in this SRFI is almost equivalent to the bytevector
API in R7RS. The only incompatibilities are that
takes a different order of arguments, and that there is no equivalent
u8vector-compare in R7RS. I see neither of these reason enough
to implement this SRFI, considering it to be subsumed by R7RS instead.
That being said, I augmented SRFI-67 with
bytevector-compare-as-list: These are natural additions to this SRFI since R7RS has bytevectors as an additional sequence type.
This is an odd one. It's not an SRFI in the strict sense, because it requests a change to the standard and not to implementations. In any case I marked it as subsumed by R7RS below because it seems that R7RS improved on the section which this SRFI requests improvements in, although not exactly in the way this SRFI asks for.
All SRFI are listed here, and marked with one of the following:
- (empty): Has yet to be looked into.
- withdrawn: It's a withdrawn SRFI.
- deprecated: Deprecated by another SRFI.
- platform: Ought to be implemented at the platform level.
- r6rs: Subsumed by R6RS in some way.
- r7rs: Subsumed by R7RS in some way.
- UNTESTED: Yet lacks a test-suite.
- DRAFT: Still in draft status.
- check: Implemented and passes its test-suite.
UNTESTED and DRAFT are capitalized to emphasize that we're not done with them yet; all other non-empty tags mean we're done with it.
Don't let the UNTESTED tag scare you off; I minimally test any
implementation in Chibi, and some are really trivial, but so long as
an SRFI has no corresponding
n.test.scm, it's UNTESTED, period.
The r7rs tag can be vague. In the simplest case the SRFI is adopted
as-is in R7RS. Sometimes there are minor tweaks. Sometimes the same
essential functionality is provided in a different way in R7RS; a good
example might be SRFI-7, though it's equivalent to
you pay attention.
- SRFI-0: platform
- SRFI-1: UNTESTED
- SRFI-2: check
- SRFI-3: withdrawn
- SRFI-4: platform
- SRFI-5: UNTESTED
- SRFI-6: r7rs
- SRFI-7: r7rs (define-library)
- SRFI-8: UNTESTED
- SRFI-9: r7rs
- SRFI-10: platform
- SRFI-11: r7rs
- SRFI-12: withdrawn
- SRFI-15: withdrawn
- SRFI-16: r7rs
- SRFI-17: UNTESTED
- SRFI-20: withdrawn
- SRFI-22: platform
- SRFI-23: r7rs
- SRFI-24: withdrawn
- SRFI-25: UNTESTED
- SRFI-26: check
- SRFI-27: UNTESTED
- SRFI-28: UNTESTED
- SRFI-30: r7rs
- SRFI-31: check
- SRFI-32: withdrawn
- SRFI-33: withdrawn
- SRFI-34: r7rs
- SRFI-35: UNTESTED
- SRFI-36: platform
- SRFI-37: UNTESTED
- SRFI-38: r7rs
- SRFI-39: r7rs
- SRFI-40: deprecated (SRFI-41)
- SRFI-41: UNTESTED
- SRFI-42: UNTESTED
- SRFI-43: UNTESTED
- SRFI-45: r7rs
- SRFI-46: r7rs
- SRFI-47: deprecated (SRFI-63)
- SRFI-48: UNTESTED
- SRFI-49: platform
- SRFI-50: withdrawn
- SRFI-51: UNTESTED
- SRFI-52: withdrawn
- SRFI-53: withdrawn
- SRFI-54: check
- SRFI-55: r7rs (import)
- SRFI-56: withdrawn
- SRFI-57: UNTESTED
- SRFI-58: platform
- SRFI-60: UNTESTED
- SRFI-61: UNTESTED
- SRFI-62: r7rs
- SRFI-63: UNTESTED
- SRFI-64: check
- SRFI-65: withdrawn
- SRFI-66: r7rs (bytevectors)
- SRFI-67: UNTESTED
- SRFI-68: withdrawn
- SRFI-69: UNTESTED
- SRFI-70: r7rs (see remarks above)
- SRFI-71: UNTESTED
- SRFI-72: platform
- SRFI-73: withdrawn
- SRFI-74: r6rs
- SRFI-75: withdrawn
- SRFI-76: withdrawn
- SRFI-77: withdrawn
- SRFI-78: UNTESTED
- SRFI-79: withdrawn
- SRFI-80: withdrawn
- SRFI-81: withdrawn
- SRFI-82: withdrawn
- SRFI-83: withdrawn
- SRFI-84: withdrawn
- SRFI-85: withdrawn
- SRFI-87: UNTESTED
- SRFI-88: platform
- SRFI-91: withdrawn
- SRFI-92: withdrawn
- SRFI-93: withdrawn
- SRFI-95: UNTESTED
- SRFI-98: r7rs
- SRFI-102: withdrawn
- SRFI-103: withdrawn
- SRFI-104: withdrawn
- SRFI-105: platform
- SRFI-106: DRAFT
- SRFI-107: platform
- SRFI-108: platform
- SRFI-109: platform
- SRFI-110: platform
- SRFI-111: UNTESTED
- SRFI-117: DRAFT
- SRFI-119: platform
- SRFI-121: DRAFT
- SRFI-122: DRAFT
- SRFI-123: DRAFT