R⁷RS (Revised⁷ Report on the Algorithmic Language Scheme) is the seventh revision of the formal specification for the Scheme programming language, published in 2013. It standardizes a minimal yet powerful core language, emphasizing lexical scoping, first-class procedures, and hygienic macros. R⁷RS introduces a library system, explicit syntax for records, and a smaller set of essential procedures compared to its predecessor R⁶RS, aiming for simplicity and portability across implementations.
1 Scope and rationale
This section outlines the motivations behind the R⁷RS specification and its relationship to other Scheme standards.
1.1 Objectives of R⁷RS
The primary goals of R⁷RS are to provide a clean, minimal core language that is portable across a wide range of implementations while maintaining consistency with the Scheme tradition.
1.1.1 Minimality and portability
R⁷RS reduces the set of required procedures and syntactic forms relative to R⁶RS. This simplification lowers the implementation burden and increases the likelihood that programs written against R⁷RS will run unchanged on different Scheme systems. Many features previously required are now optional, and the standard defines a straightforward way for programs to detect available capabilities.
1.1.2 Backward compatibility and divergence
R⁷RS is designed to be largely backward compatible with R⁶RS, but some incompatible changes were made to achieve a smaller core. Programs relying on R⁶RS features that were removed (such as shared‑mutable‑object support) must be adapted. The report explicitly documents these divergences to assist implementors and users.
1.2 Relationship to R⁶RS and other Scheme standards
R⁷RS supersedes R⁶RS (published in 2007) and coexists with earlier reports (R⁵RS, R⁴RS, etc.). It also acknowledges the existence of other Scheme standards such as the IEEE Scheme standard and the broader Scheme Request for Implementation (SRFI) process. R⁷RS does not attempt to unify all Scheme dialects but rather provides a common subset that implementations are encouraged to support.
2 Core language
The core language of R⁷RS describes the fundamental syntax, data types, and expression forms that every conforming implementation must provide.
2.1 Lexical syntax and semantics
R⁷RS defines the lexical rules for identifiers, literals, and comments.
2.1.1 Identifiers, numbers, and boolean literals
Identifiers follow the Scheme tradition: they consist of letters, digits, and certain special characters (e.g., !, ?, -). Numbers may be exact or inexact, and can be written in decimal, binary, octal, or hexadecimal notation. Boolean literals are #t and #f. Strings and characters have their usual syntax: "hello" and #\a.
2.1.2 Comments and datum labels
Line comments begin with ; and extend to the end of the line. Block comments are delimited by `# | and | #. Datum labels allow sharing of structure in external representation: #n= marks a label and #n#` refers to it, enabling the representation of cyclic or shared data. |
|---|
2.2 Data types
R⁷RS specifies a fixed set of disjoint data types.
2.2.1 Numbers (exact/inexact, fixnum, flonum)
Numbers are either exact (rational) or inexact (floating‑point). The standard distinguishes between fixnums (exact integers in a specific range) and flonums (inexact real numbers). Many arithmetic procedures accept any numeric type and perform automatic coercion.
2.2.2 Pairs, lists, and vectors
Pairs (constructed with cons) form the basis of linked lists. The empty list is '(). Vectors are fixed‑length sequences indexed by integers. Both pairs and vectors are mutable by default, though immutable variants can be created.
2.2.3 Characters, strings, and bytevectors
Characters represent Unicode code points. Strings are mutable sequences of characters. Bytevectors are vectors of exact integers in the range 0–255. All three support standard operations such as length, indexing, and conversion.
2.2.4 Symbols and booleans
Symbols are interned strings used as identifiers and literal data. Booleans are the two values #t and #f. Only the boolean #f is treated as false in conditionals; all other values are true.
2.2.5 Procedures and ports
Procedures are first‑class objects; they can be created dynamically and passed as arguments. Ports are abstractions for input/output. Ports may be textual or binary, and can be opened for reading, writing, or both.
2.3 Expressions and definitions
R⁷RS defines a small set of core expression types and a larger set of derived forms.
2.3.1 Primitive expression types
The language is built on a few essential expression forms.
2.3.1.1 Variable references and literals
A variable reference is a symbol that evaluates to its current binding. A literal is introduced with the quote form (abbreviated ') and evaluates to itself.
2.3.1.2 Procedure calls and conditionals
Procedure calls are written as (operator operand ...). The operator and operands are evaluated, and the operator is applied to the operands. Conditionals use if: (if test consequent alternate).
2.3.2 Derived expression types
Several common syntactic forms are defined as derived (i.e., they can be expressed in terms of primitives). Examples include cond, case, and, or, let, let*, letrec, do, and begin.
2.3.2.1 Handling of iterative constructs
Iteration is typically expressed using named let (the “named‑let” idiom) or the do loop. Both are derived forms; the core language does not provide an explicit while or for construct.
2.3.3 Macros (syntax-rules)
Hygienic macros are defined with syntax-rules, a pattern‑based macro system introduced in R⁵RS and retained in R⁷RS.
2.3.3.1 Pattern language and hygiene
Macro patterns match the input form and produce a template. The macro expander automatically renames all bound variables to prevent accidental capture (hygiene). syntax-rules supports ellipsis (...) for repetition and can generate identifiers using datum->syntax.
3 Library system
R⁷RS introduces a formal library system for modular programming.
3.1 Import and export declarations
A library is defined using the define-library form, which lists imports, exports, and the body.
3.1.1 Named libraries and explicit versioning
Libraries have a name (a list of symbols, e.g., (scheme base)) and can optionally specify a version. Imports and exports are declared using import and export clauses within the library definition.
3.1.2 R⁷RS standard libraries
The standard defines a set of required libraries, each providing a specific subset of functionality. The most important is (scheme base), which contains the core procedures and syntax. Other libraries extend the language with I/O, numbers, time, and more.
3.2 Standard library overview
This subsection lists the standard libraries defined by R⁷RS, each of which is described in more detail later.
3.2.1 (scheme base) – core procedures
Provides arithmetic, list operations, equality predicates, I/O primitives, and control structures. All programs implicitly import this library.
3.2.2 (scheme case-lambda) – case-lambda syntax
Defines case-lambda, a form for creating procedures that dispatch on number of arguments.
3.2.3 (scheme char) – character utilities
Offers character predicates and conversion routines (e.g., char-upcase, char-alphabetic?).
3.2.4 (scheme complex) – complex arithmetic
Provides make-rectangular, make-polar, real-part, imag-part, magnitude, and angle.
3.2.5 (scheme cxr) – nested pair accessors
Defines procedures like caar, cadr, cddr, etc., up to four levels of nesting (e.g., cddadr).
3.2.6 (scheme eval) – evaluation environment
Provides eval, which evaluates an expression in a given environment.
3.2.7 (scheme file) – file ports and operations
Offers open-input-file, open-output-file, call-with-input-file, call-with-output-file, and related procedures.
3.2.8 (scheme inexact) – real inexact arithmetic
Defines sin, cos, tan, asin, acos, atan, exp, log, sqrt, and similar mathematical functions that operate on inexact reals.
3.2.9 (scheme lazy) – delayed evaluation
Exports delay, force, delay-force, make-promise, and promise? for lazy evaluation.
3.2.10 (scheme load) – loading programs
Provides load to read and evaluate a file as a program.
3.2.11 (scheme process-context) – command-line arguments
Gives access to the command‑line arguments via command-line and command-line-arguments.
3.2.12 (scheme read) – reading syntax
Contains read and read-string for parsing S‑expressions from a port.
3.2.13 (scheme repl) – interactive environment
Defines interaction-environment and related procedures for REPL (read‑eval‑print‑loop) support.
3.2.14 (scheme time) – current time and duration
Provides current-second, current-jiffy, jiffies-per-second, and operations for duration arithmetic.
3.2.15 (scheme write) – writing syntax
Contains write, display, and write-string for outputting S‑expressions.
4 Records
Records are user‑defined data types with named fields.
4.1 Functional records (define-record-type)
The define-record-type form creates a new record type with a constructor, predicate, and accessors.
4.1.1 Constructor, predicate, and accessors
After a define-record-type definition, a constructor procedure (typically named make-<type>) creates instances. A predicate (<type>?) tests membership. Accessors (<type>-<field>) retrieve field values.
4.1.2 Mutable and immutable variants
By default, fields are immutable; the mutable keyword can be used to declare mutable fields. Mutable fields have accompanying mutators (<type>-<field>-set!).
4.1.3 Record introspection and reflection
The procedures record?, record-type-descriptor, and record-type-name allow runtime inspection of record types. A record type descriptor (RTD) can be used to access or mutate fields generically via record->vector and vector->record.
5 Error handling and exceptions
R⁷RS provides a simple exception system.
5.1 Error and assertion procedures
The error procedure raises an exception with a message and irrtants. assert checks a condition and calls error if it is false. assertion-violation is a variant for assertion failures.
5.2 Guard and with-exception-handler
guard is a derived form that evaluates an expression and catches exceptions in a handler. with-exception-handler is a lower‑level primitive that installs a handler for the dynamic extent of a thunk. Exceptions are objects, typically implementation‑defined but must support message-condition? and irritants-condition?.
6 Standard libraries details
This section expands on selected libraries from subsection 3.2.
6.1 (scheme base) in-depth
The (scheme base) library contains the bulk of the language.
6.1.1 Arithmetic
Provides the full numeric tower: +, -, *, /, quotient, remainder, modulo, floor, ceiling, truncate, round, etc. Exact numbers support rational arithmetic; inexact numbers follow IEEE floating‑point semantics.
6.1.1.1 Comparators and rounding
Comparators include =, <, >, <=, >=. Rounding procedures are floor, ceiling, truncate, and round. Additional numeric predicates (zero?, positive?, negative?, odd?, even?) are provided.
6.1.2 Lists and mapping
List constructors (list, cons), accessors (car, cdr, list-ref), and procedures like length, append, reverse, member, assoc are defined. Mapping procedures include map, for-each, filter, fold-left, fold-right (the latter two are optional but widely supported).
6.1.3 Iteration constructs
Iteration is achieved with named let, do, and higher‑order procedures like map and for-each. The library also includes call/cc for full continuations.
6.2 (scheme lazy) and promises
The (scheme lazy) library supports lazy evaluation.
6.2.1 delay, force, and eager
delay creates a promise, force evaluates a promise (caching the result), and eager makes a promise that has already been evaluated. delay-force is a variant that avoids unnecessary thunks.
6.3 (scheme read) and write
These libraries handle reading and writing S‑expressions.
6.3.1 Handling of circular structures
Both read and write support datum labels (see 2.1.2). When writing, write automatically uses labels for shared or circular substructures. read recognizes these labels and reconstructs the shared structure.
7 Implementation considerations
This section provides guidance for implementors and discusses the rationale behind certain changes.
7.1 Portability guidelines
Implementations should aim to support the full R⁷RS core and libraries.
7.1.1 Optional features and their detection
Many features (e.g., exact ratios, full numeric tower, mutable strings) are optional. Programs can use cond-expand or the environment procedure to test for the presence of specific features at compile time.
7.1.2 Interaction with host system
The report does not specify how Scheme interacts with the operating system. Implementations may provide additional libraries (e.g., for file system access, networking) outside the standard. The (scheme process-context) library is the only standard interface to the host environment.
7.2 Rationale for departures from R⁶RS
R⁷RS intentionally reverted some R⁶RS decisions.
7.2.1 Removal of shared-mutable-objects support
R⁶RS required that eq? return #f for distinct mutable objects even if they share the same underlying storage. This was found to be overly restrictive and difficult to implement efficiently; R⁷RS leaves the behavior of eq? on mutable objects unspecified.
7.2.2 Simplification of library versioning
R⁶RS mandated a complex versioning scheme with conditional imports. R⁷RS simplifies this to a single optional version number per library, and removes conditional import syntax. This reduces implementation complexity and encourages direct library specification.