Back Contents Next

1. Overview of Better Scheme

1.1 Semantics

This section gives an overview of Better Scheme's semantics. A detailed informal semantics is the subject of chapters 3. Basic Concepts through 5. Standard Entities.

Following Algol and Scheme, Better Scheme is a statically scoped programming language. Each use of a variable is associated with a lexically apparent binding of that variable.

Better Scheme might be said not to have types, since all entities in Better Scheme are functions or their close cousins macros and continuations. Types may be associated with a group of functions based on some common behavior. Thus any types are associated with values rather than with variables.

All entities created in the course of a Better Scheme computation, including functions, macros and continuations, have unlimited extent. No entity is ever destroyed. The reason that implementations of Better Scheme do not normally run out of storage is that they are permitted to reclaim the storage occupied by an entity if they can prove that the entity cannot possibly matter to any future computation. This is known as garbage collection. Other languages in which most entities have unlimited extent include APL, Java and other Lisp dialects.

Implementations of Better Scheme are required to be properly tail-recursive. This allows the execution of an iterative computation in constant space, even if the iterative computation is described by a syntactically recursive function. Thus with a properly tail-recursive implementation, iteration can be expressed using the ordinary function-call mechanics, so that special iteration constructs are useful only as syntactic sugar (see section 3.5 Proper Tail Recursion.).

Better Scheme functions and macros are entities in their own right. They can be created dynamically, stored in data structures, returned as results of functions, and so on. Other languages with these properties include Common Lisp and ML. Better Scheme extends the power of functions by makeing all functions of more than one argument into curried functions.

One distinguishing feature of Scheme & Better Scheme is that continuations, which in most other languages only operate behind the scenes, also have "first-class" status. Continuations are useful for implementing a wide variety of advanced control constructs, including non-local exits, backtracking, and coroutines (see section 5.2 Flow Control).

Hygienic macros provide a way to manipulate arguments before they are evaluated. Better Scheme allows great control of evaluation by providing the evaluative operator (a comma) which can be used to force the evaluation of a function argument and the ability to include literals and create none hygienic macros.

Better Scheme's model of arithmetic is designed to remain as independent as possible of the particular ways in which numbers are represented within a computer. In Better Scheme, every integer is a rational number, every rational is a real, and every real is a complex number. Thus the distinction between integer and real arithmetic, so important to many programming languages, does not appear in Scheme. In its place is a distinction between exact arithmetic, which corresponds to the mathematical ideal, and inexact arithmetic on approximations. As in Common Lisp, exact arithmetic is not limited to integers.

1.2 Syntax

Better Scheme, like Scheme, employs a fully parenthesized prefix notation for programs and (other) data; the grammar of Better Scheme generates a sub-language of the language used for data. An important consequence of this simple, uniform representation is the susceptibility of Better Scheme programs and data to uniform treatment by other Better Scheme programs.

For a more detailed explanation of the syntax of Better Scheme see sections 2. Lexical Structure and 4. Expressions.

1.3 Notation and Terminology

1.3.1 Primitive, Library and Optional features

It is required that every implementation of Better Scheme support all features that are not marked as optional. Implementations are free to omit optional features of Better Scheme or to add extensions, provided the extensions are not in conflict with the language reported here. In particular, implementations must support portable code by providing a syntactic mode that preempts no lexical conventions of this report.

To aid in understanding and implementing Better Scheme, many features are marked as library. These can be easily implemented in terms of the other, primitive, features. They are redundant in the strict sense of the word, but they capture common patterns of usage, and are therefore provided as convenient abbreviations.

1.3.2 Error Situations and Unspecified Behavior

When speaking of an error situation, this report uses the phrase "an error is signaled" to indicate that implementations must detect and report the error. If such wording does not appear in the discussion of an error, then implementations are not required to detect or report the error, though they are encouraged to do so. An error situation that implementations are not required to detect is usually referred to simply as "an error."

For example, it is an error for a function to be passed an argument that the function is not explicitly specified to handle, even though such domain errors are seldom mentioned in this report. Implementations may extend a function's domain of definition to include such arguments.

This report uses the phrase "may report a violation of an implementation restriction" to indicate circumstances under which an implementation is permitted to report that it is unable to continue execution of a correct program because of some restriction imposed by the implementation. Implementation restrictions are of course discouraged, but implementations are encouraged to report violations of implementation restrictions. For example, an implementation may report a violation of an implementation restriction if it does not have enough storage to run a program.

1.3.3 Entry Format

Sections 4. Expressions and 5. Standard Entities are organized into entries. Each entry describes one language feature or a group of related features, where a feature is either a syntactic construct or a built-in entity. An entry begins with one or more header lines of the form

category: template

for required, primitive features, or

qualifier category: template

where qualifier is either "library" or "optional" as defined in section 1.3.1 Primitive, Library and Optional features.

If category is "macro", the entry describes an expression type, and the template gives the syntax of the expression type. Components of expressions are designated by syntactic variables, which are written using angle brackets, for example <expression> and <symbol>. Syntactic variables should be understood to denote segments of program text; for example, <expression> stands for any string of characters which is a syntactically valid expression. The notation

<thing1> ...

indicates zero or more occurrences of a <thing>, and

<thing1> <thing> ...

indicates one or more occurrences of a <thing>.

If category is "function", then the entry describes a function, and the header line gives a template for a call to the function. Argument names in the template are italicized. Thus the header line

function: (vector-ref vector k)

indicates that the built-in function vector-ref takes two arguments, a vector vector and an exact non-negative integer k (see below). The header lines

function: (make-vector k)
function: (make-vector k fill)

indicate that the make-vector procedure must be defined to take either one or two arguments.

It is an error for an operation to be presented with an argument that it is not specified to handle. For succinctness, we follow the convention that if an argument name is also the name of a type listed in section 3.2 Disjointness of Types, then that argument must be of the named type. For example, the header line for vector-ref given above dictates that the first argument to vector-ref must be a vector. The following naming conventions also imply type restrictions:

obj any object
list, list1, ... listj, ... list (see section 5.6.2 Pairs and Lists)
z, z1, ... zj, ... complex number
x, x1, ... xj, ... real number
y, y1, ... yj, ... real number
q, q1, ... qj, ... rational number
n, n1, ... nj, ... integer
k, k1, ... kj, ... exact non-negative integer

1.3.4 Evaluation Examples

The symbol used in program examples should be read "evaluates to." For example,

(* 5 8) 40

means that the expression (* 5 8) evaluates to the object 40. Or, more precisely: the expression given by the sequence of characters "(* 5 8)" evaluates, in the initial environment, to an object that may be represented externally by the sequence of characters "40" (see section 3.3 External Representations).

1.3.5 Naming Conventions

By convention, the names of functions that always return a boolean value end in "?". Such functions are called predicates.

By convention, the names of functions that store values into previously allocated locations (see section 3.4 Storage Model) end in "!". Such functions are called mutation functions. By convention, the value returned by a mutation procedure is #void unless a boolean is used to signal possible failure.

By convention, "->" appears within the names of functions that take an object of one type and return an analogous object of another type. For example, list->vector takes a list and returns a vector whose elements are the same as those of the list.



Back Contents Next

jwalker@cs.oberlin.edu