A Scheme program consists of one or more import declarations followed by a sequence of expressions and definitions. Import declarations specify the libraries on which a program or library depends; a subset of the identifiers exported by the libraries are made available to the program. Expressions are described in chapter 4. Definitions are either variable definitions, syntax definitions, or record-type definitions, all of which are explained in this chapter. They are valid in some, but not all, contexts where expressions are allowed, specifically at the outermost level of a <program> and at the beginning of a <body>.
At the outermost level of a program, (begin <expression or definition1> …) is equivalent to the sequence of expressions and definitions in the begin. Similarly, in a <body>, (begin <definition1> …) is equivalent to the sequence <definition1> …. Macros can expand into such begin forms. For the formal definition, see 4.2.3.
Import declarations and definitions cause bindings to be created in the global environment or modify the value of existing global bindings. The initial environment of a program is empty, so at least one import declaration is needed to introduce initial bindings.
Expressions occurring at the outermost level of a program do not create any bindings. They are executed in order when the program is invoked or loaded, and typically perform some kind of initialization.
Programs and libraries are typically stored in files, although in some implementations they can be entered interactively into a running Scheme system. Other paradigms are possible. Implementations which store libraries in files should document the mapping from the name of a library to its location in the file system.
An import declaration takes the following form:
(import <import-set> …)
<library name>
(only <import set> <identifier> …)
(except <import set> <identifier> …)
(prefix <import set> <identifier>)
(rename <import set>
(<identifier1> <identifier2>) …)
In the first form, all of the identifiers in the named library’s export clauses are imported with the same names (or the exported names if exported with rename). The additional <import set> forms modify this set as follows:
only produces a subset of the given <import set> including only the listed identifiers (after any renaming). It is an error if any of the listed identifiers are not found in the original set.
except produces a subset of the given <import set>, excluding the listed identifiers (after any renaming). It is an error if any of the listed identifiers are not found in the original set.
rename modifies the given <import set>, replacing each instance of <identifier1> with <identifier2>. It is an error if any of the listed <identifier1>s are not found in the original set.
prefix automatically renames all identifiers in the given <import set>, prefixing each with the specified <identifier>.
In a program or library declaration, it is an error to import the same identifier more than once with different bindings, or to redefine or mutate an imported binding with a definition or with set!, or to refer to an identifier before it is imported. However, a REPL should permit these actions.
A variable definition binds one or more identifiers and specifies an initial value for each of them. The simplest kind of variable definition takes one of the following forms:
(define <variable> <expression>)
(define (<variable> <formals>) <body>)
<Formals> are either a sequence of zero or more variables, or a sequence of one or more variables followed by a space-delimited period and another variable (as in a lambda expression). This form is equivalent to
(define <variable>(define (<variable> . <formal>) <body>)
<Formal> is a single variable. This form is equivalent to
(define <variable>
At the outermost level of a program, a definition
(define <variable> <expression>)has essentially the same effect as the assignment expression (set! <variable> <expression>)if <variable> is bound to a non-syntax value. However, if <variable> is not bound, or is a syntactic keyword, then the definition will bind <variable> to a new location before performing the assignment, whereas it would be an error to perform a set! on an unboundvariable.(define add3
Definitions can occur at the beginning of a <body> (that is, the body of a lambda, let, let*, letrec, letrec*, let-values, let*-values, let-syntax, letrec-syntax, parameterize, guard, or case-lambda). Note that such a body might not be apparent until after expansion of other syntax. Such definitions are known as internal definitionsas opposed to the global definitions described above. The variables defined by internal definitions are local to the <body>. That is, <variable> is bound rather than assigned, and the region of the binding is the entire <body>. For example,
(let ((x 5))
(let ((x 5))
It is an error to define the same identifier more than once in the same <body>.
Wherever an internal definition can occur, (begin <definition1> …) is equivalent to the sequence of definitions that form the body of the begin.
Another kind of definition is provided by define-values, which creates multiple definitions from a single expression returning multiple values. It is allowed wherever define is allowed.
It is an error if a variable appears more than once in the set of <formals>.
Semantics: <Expression> is evaluated, and the <formals> are bound to the return values in the same way that the <formals> in a lambda expression are matched to the arguments in a procedure call.
(define-values (x y) (exact-integer-sqrt 17))
Syntax definitions have this form:
(define-syntax <keyword> <transformer spec>)
<Keyword> is an identifier, and the <transformer spec> is an instance of syntax-rules. Like variable definitions, syntax definitions can appear at the outermost level or nested within a body.
If the define-syntax occurs at the outermost level, then the global syntactic environment is extended by binding the <keyword> to the specified transformer, but previous expansions of any global binding for <keyword> remain unchanged. Otherwise, it is an internal syntax definition, and is local to the <body> in which it is defined. Any use of a syntax keyword before its corresponding definition is an error. In particular, a use that precedes an inner definition will not apply an outer definition.
(let ((x 1) (y 2))
Macros can expand into definitions in any context that permits them. However, it is an error for a definition to define an identifier whose binding has to be known in order to determine the meaning of the definition itself, or of any preceding definition that belongs to the same group of internal definitions. Similarly, it is an error for an internal definition to define an identifier whose binding has to be known in order to determine the boundary between the internal definitions and the expressions of the body it belongs to. For example, the following are errors:
(define define 3)
Record-type definitions are used to introduce new data types, called record types. Like other definitions, they can appear either at the outermost level or in a body. The values of a record type are called records and are aggregations of zero or more fields, each of which holds a single location. A predicate, a constructor, and field accessors and mutators are defined for each record type.
Syntax: <name> and <pred> are identifiers. The <constructor> is of the form
(<constructor name> <field name> …)and each <field> is either of the form (<field name> <accessor name>)or of the form (<field name> <accessor name> <modifier name>) It is an error for the same identifier to occur more than once as a field name. It is also an error for the same identifier to occur more than once as an accessor or mutator name.The define-record-type construct is generative: each use creates a new record type that is distinct from all existing types, including Scheme’s predefined types and other record types — even record types of the same name or structure.
An instance of define-record-type is equivalent to the following definitions:
<name> is bound to a representation of the record type itself. This may be a run-time object or a purely syntactic representation. The representation is not utilized in this report, but it serves as a means to identify the record type for use by further language extensions.
<constructor name> is bound to a procedure that takes as many arguments as there are <field name>s in the (<constructor name> …) subexpression and returns a new record of type <name>. Fields whose names are listed with <constructor name> have the corresponding argument as their initial value. The initial values of all other fields are unspecified. It is an error for a field name to appear in <constructor> but not as a <field name>.
<pred> is bound to a predicate that returns #t when given a value returned by the procedure bound to <constructor name> and #f for everything else.
Each <accessor name> is bound to a procedure that takes a record of type <name> and returns the current value of the corresponding field. It is an error to pass an accessor a value which is not a record of the appropriate type.
Each <modifier name> is bound to a procedure that takes a record of type <name> and a value which becomes the new value of the corresponding field; an unspecified value is returned. It is an error to pass a modifier a first argument which is not a record of the appropriate type.
For instance, the following record-type definition
(define-record-type <pare>
(pare? (kons 1 2)) ⟹ #t
Libraries provide a way to organize Scheme programs into reusable parts with explicitly defined interfaces to the rest of the program. This section defines the notation and semantics for libraries.
A library definition takes the following form:
(define-library <library name>
A <library declaration> is any of:
(export <export spec> …)
(import <import set> …)
(begin <command or definition> …)
(include <filename1> <filename2> …)
(include-ci <filename1> <filename2> …)
(include-library-declarations <filename1> <filename2> …)
(cond-expand <ce-clause1> <ce-clause2> …)
An export declaration specifies a list of identifiers which can be made visible to other libraries or programs. An <export spec> takes one of the following forms:
<identifier>
(rename <identifier1> <identifier2>)
In an <export spec>, an <identifier> names a single binding defined within or imported into the library, where the external name for the export is the same as the name of the binding within the library. A rename spec exports the binding defined within or imported into the library and named by <identifier1> in each (<identifier1> <identifier2>) pairing, using <identifier2> as the external name.
An import declaration provides a way to import the identifiers exported by another library. It has the same syntax and semantics as an import declaration used in a program or at the REPL (see section 5.2).
The begin, include, and include-ci declarations are used to specify the body of the library. They have the same syntax and semantics as the corresponding expression types. This form of begin is analogous to, but not the same as, the two types of begin defined in section 4.2.3.
The include-library-declarations declaration is similar to include except that the contents of the file are spliced directly into the current library definition. This can be used, for example, to share the same export declaration among multiple libraries as a simple form of library interface.
The cond-expand declaration has the same syntax and semantics as the cond-expand expression type, except that it expands to spliced-in library declarations rather than expressions enclosed in begin.
One possible implementation of libraries is as follows: After all cond-expand library declarations are expanded, a new environment is constructed for the library consisting of all imported bindings. The expressions from all begin, include and include-ci library declarations are expanded in that environment in the order in which they occur in the library. Alternatively, cond-expand and import declarations may be processed in left to right order interspersed with the processing of other declarations, with the environment growing as imported bindings are added to it by each import declaration.
When a library is loaded, its expressions are executed in textual order. If a library’s definitions are referenced in the expanded form of a program or library body, then that library must be loaded before the expanded program or library body is evaluated. This rule applies transitively. If a library is imported by more than one program or library, it may possibly be loaded additional times.
Similarly, during the expansion of a library (foo), if any syntax keywords imported from another library (bar) are needed to expand the library, then the library (bar) must be expanded and its syntax definitions evaluated before the expansion of (foo).
Regardless of the number of times that a library is loaded, each program or library that imports bindings from a library must do so from a single loading of that library, regardless of the number of import declarations in which it appears. That is, (import (only (foo) a)) followed by (import (only (foo) b)) has the same effect as (import (only (foo) a b)).
The following example shows how a program can be divided into libraries plus a relatively small main program [16]. If the main program is entered into a REPL, it is not necessary to import the base library.
(define-library (example grid)
Implementations may provide an interactive session called a REPL (Read-Eval-Print Loop), where import declarations, expressions and definitions can be entered and evaluated one at a time. For convenience and ease of use, the global Scheme environment in a REPL must not be empty, but must start out with at least the bindings provided by the base library. This library includes the core syntax of Scheme and generally useful procedures that manipulate data. For example, the variable abs is bound to a procedure of one argument that computes the absolute value of a number, and the variable + is bound to a procedure that computes sums. The full list of (scheme base) bindings can be found in Appendix A.
Implementations may provide an initial REPL environment which behaves as if all possible variables are bound to locations, most of which contain unspecified values. Top level REPL definitions in such an implementation are truly equivalent to assignments, unless the identifier is defined as a syntax keyword.
An implementation may provide a mode of operation in which the REPL reads its input from a file. Such a file is not, in general, the same as a program, because it can contain import declarations in places other than the beginning.