2Procedures

A procedure is an abstraction of an operation over objects. The operation thus abstracted over may be performed by a call to the procedure. When a procedure is called, it receives a number of inputs, referred to as its arguments. The procedure call processes those arguments either according to a specification defined in this report or by an implementation, or by evaluating some Scheme code which operates on those arguments, to perform the operation and produce its outputs. The procedure then returns its outputs to the continuation of the expression which called it. A procedure whose operation is defined by Scheme code is created by the lambda or case-lambda expressions: the arguments to the procedure are made available to that code as variables bound within the region of that code, which is a body (see Section 2.6, “Bodies”). Additional inputs to the procedure may come from variables whose region encompasses the corresponding lambda or case-lambda expression.

Scheme procedures are also objects in their own right. Procedures can be created dynamically, stored in data structures, returned as results of procedures, and so on. Many predefined operations of Scheme are provided not by syntax, but by variables whose values are procedures. The + operation, for example, which receives special syntactic treatment in many other languages, is just a regular identifier in Scheme, bound to a procedure that adds number objects.

All procedure objects in Scheme are conceptually associated with location tags, in order to make the eq? and eqv? procedures (section ???) work on procedures. The nature of this location tag is unspecified: the location tag itself cannot be directly treated as an object in Scheme; it is required only to have a defined equivalence relation for the purposes of the internal workings of eq? and eqv?.

2.1Rationale

Besides their obvious uses, procedures have traditionally been used in some Scheme programs as a form of data abstraction for object-oriented programming and similar techniques (see for example AbelsonAndSussman96 section 2.1.3). This makes it convenient to have a form of equivalence predicate defined over them, as for other Scheme data objects. However, treating lambda as a data constructor subject to the usual requirement to return a freshly-allocated object upon each evaluation (in the same way as, for example, the cons procedure) disallows some useful compiler optimizations for the more common case of using lambda to abstract a series of operations, rather than a collection of data.

A future fascicle will define a data constructor for procedures which guarantees that every evaluation creates a procedure object which is distinct from every other object in the sense of eqv? and eq?. A future Scheme report may then make the equivalence of all other procedures under eq? and eqv? unspecified. (The R6RS already made this change, but neglected to provide a suitable alternative for creating procedures which are actually used as data, so the change was reverted by the small language report.)

2.2Description

Every named procedure defined by this report has a single location tag distinct from the location tag of procedures with distinct names. The exception is if this report describes one procedure as an alias of another, in which case the two procedures may or may not have distinct location tags.

2.3Expressions and definitions

All main forms in Scheme program and library code can be categorized as either definitions or expressions.

Definitions may appear directly within a program, a library , or a body (see section Section 2.6, “Bodies”). They may also appear within a begin form (see section ???) or other splicing form that appears within one of the contexts where a definition may appear. A definition has the effect of binding one or more identifiers to variables or syntax keywords within the region of that program, library, or body in which it is found, and within any environments created by extending the environment in place in that region. A definition which appears within a library or splicing form within a library has the effect of allowing the identifiers it names to be exported from that library . A definition conceptually does not evaluate to any value or values, although a definition form which is passed to the eval procedure may cause that procedure call to return a value .

Expressions evaluate to a value or values (see section Section 2.5, “Multiple return values”). They may contain a region for an identifier or identifiers created by the expression itself, or by definitions which form part of the expression, but expressions do not create bindings in the region surrounding themselves. Expressions may occur within other expressions, as well as within definitions to specify the values of variables or the transformers for syntax keywords that are bound by the definition. All syntactic forms defined in this report are expressions unless explicitly stated to be definitions.

When an expression appears within a definition, or within a syntactic form or procedure call that changes the value of a variable or the value stored in some other location, the expression which denotes the new value to be stored in that location is said to be on the right-hand side of the definition, assignment form, or procedure call. The remaining subforms or arguments, which denote the location which is to have a new value stored in it, are said to be on the left-hand side.

When syntactic forms are specified in this report, the rule expression means any form which is an expression, and definition means any form which is a definition. Definition or expression means either a definition or an expression, although the final sequence of forms within any context where either is allowed must conform to the restrictions on definitions and expressions which apply within that context. For example, one such restriction which applies to all contexts where definitions are allowed is that no definition form may attempt to bind an identifier which another definition form in the same context also binds. It is a syntax violation to use a definition in a context where only expressions are allowed.

Some main forms in Scheme also contain auxiliary forms which are neither definitions nor expressions. Such auxiliary forms, unlike main forms, have no meaning or validity outside of by the main form to which they belong. Examples of such auxiliary forms include the formals clause of a lambda expression (see section Section 2, “Procedures”), the left-hand side of define forms and the bindings clauses of let expressions (see section ???), and each cond clause of a cond expression (see section ???).

2.4Continuations and dynamic extents

NOTE: This section will be extended by a future fascicle.

Whenever a Scheme expression is evaluated there is a continuation waiting for the result of the expression. The continuation represents an entire (default) future for the computation. For example, informally the continuation of 3 in the expression (+ 1 3) adds 1 to it.

Normally these ubiquitous continuations are hidden behind the scenes and programmers do not think much about them. However, one distinguishing feature of Scheme is that continuations, which in most other languages only operate behind the scenes, also have first-class status. Continuations may be captured in first-class procedure objects and returned to later by subsequent calls to these procedures. Using this mechanism, continuations in Scheme may never be returned to, or they may be returned to multiple times. Thus, the evaluation of any expression or sequence of expressions in Scheme can be interrupted and restarted multiple times by capture and return to a continuation.

For a procedure call, the time between when it is initiated and when it returns is called its dynamic extent. Capture of continuations allows re-entering a dynamic extent after its procedure call has returned. Thus, the dynamic extent of a call may not be a single, connected time period.

2.5Multiple return values

A Scheme expression can evaluate to an arbitrary finite number of values. These values are passed to the expression’s continuation.

Not all continuations accept any number of values. For example, a continuation that accepts the argument to a procedure call is guaranteed to accept exactly one value (see section Chapter 3, Basic expression types).

A number of forms in Scheme have sequences of expressions as subforms that are evaluated sequentially, with the return values of all but the last expression being discarded. The continuations discarding these values accept any number of values.

2.6Bodies

Many syntactic forms in Scheme are specified as containing a body. (In order to distinguish bodies from the code inside of libraries and top-level programs, a body is sometimes referred to as a procedure body, because lambda is the fundamental form for the implementation of forms which use bodies.) A body is a region for keywords and variables created by definitions directly within the body, or inside of splicing constructs (such as begin, splicing-let-syntax, and splicing-letrec-syntax) within the body. A body is concluded with an expression and may also contain additional expressions before, between, or after the definitions.

Bodies are first processed by the expander according to the process defined in , a process which also removes any splicing constructs by replacing them with their expanded subforms. The expander also takes note of the set of identifier names bound by syntax or variable definitions within the entire region of the body. It is a syntax violation if any definition attempts to bind the same identifier more than once, or attempts to bind the same identifier as another definition within the same body (including in any splicing constructs).

After this process, a body consists only of variable definitions and expressions in their fully expanded core forms. These are further processed for evaluation in groups as follows. An expanded body has the form

variable definition–expression group ... expression

The expression is referred to as the final expression of the body. A variable definition–expression group has the form

variable definition ... expression

A variable definition is any implementation-dependent core form which is a definition form for variables. The expressions of a variable definition–expression group are referred to as the non-final expressions of the body. It is a syntax violation if the expanded content of a body does not conform to these rules.

Each variable definition–expression group is converted into the equivalent of a letrec*-values (see section ???) for the variable definitions in that group, although this letrec*-values does not contain a body itself but only a sequence of expressions, which are evaluated from left to right. The sequence of expressions consists of the expressions within the respective variable definition–expression group, followed by the corresponding conversion of the next variable definition–expression group, or by the final expression if there are no further variable definition–expression groups. Implementations should signal a syntax violation if the expansion of the right-hand side of any variable definition, or the expansion of any expression, refers to the name of any identifier which is a variable defined by a variable definition–expression group which is to the right of the variable definition–expression group in which it appears.

RationaleScheme has traditionally only allowed a single group of definitions at the head of a body, followed by at least one expression. Experience has shown that it is often useful to be able to mix the two types of forms in bodies, especially for error checking and logging of intermediate results. However, typical optimized implementation techniques for the semantics of the letrec or letrec* underlying a traditional Scheme body work only when the right-hand sides of definitions, and by extension the entire block of definitions, are free of side-effects or uses of first-class continuations. Since non-final expressions in a body are only useful for their side-effects or continuation invocations, simply incorporating expressions into the sequence of letrec* bindings invariably inhibits these optimizations. The compilation scheme described here provides the convenience of mixing definitions and expressions in any order, while ultimately grouping the definitions so that optimization can still happen as in implementations of previous revisions of this report. Since the expander still treats syntax keyword bindings throughout the whole body as belonging to a single region, and implementations should treat attempts at forward reference to a variable defined in a future group of definitions and expressions as a syntax violation, the property that a body is a single region for bindings is maintained: the only practical restriction is that it is not possible to create mutually-recursive definitions between distinct variable definition–expression groups, which is necessary to ensure each letrec*-values equivalent form in the transformed body can still be optimized.

2.6.1Issue

The syntax and semantics of bodies described above represent an initial attempt to find a satisfactory means of allowing Scheme programmers to mix definitions and expressions in any order within bodies, as requested by voters on the Stygian Blue ballot. They correspond to a variant of semantics originally proposed by Sergei Egorov in SRFI 251, adapted for the expansion order originally specified by R6RS and described in the macrological fascicle. There is also a permissive provision allowing implementations to adopt semantics more like those of SRFI 245 or R6RS program bodies, which do not restrict forward reference between different variable definition–expression groups. This permissive provision is the should in the recommendation to signal a syntax violation in the case of a reference to a variable in a subsequent variable definition–expression group.

The working group is unsatisfied with the creation of implicit lexical contours by variable definition–expression groups, especially considering the behaviour of identifier syntax defined in the body (which may inadvertently flout good Scheme style by not behaving exactly like a variable) and the behaviour of macros which may expand to a combination of a definition and an expression. The R6RS program body semantics are also problematic for the optimization-related reasons described above in the rationale. Further, with semantics derived from those of R6RS program bodies, it would not be safely possible to use continuations to return twice from any expression in a body before that body’s final definition. (The R6RS encourages implementations to raise a violation exception in this case.) Note that the permissive provision above implies that implementations which take advantage of it cannot impose such a restriction on multiple return from expressions.

The working group is especially keen to receive feedback on this matter from the Scheme community.

DescriptionThe continuations of all of the non-final expressions within a body (i.e. of the expanded expressions within the created letrec*-values equivalent) accept any number of values and discard them. The continuation of the final expression of a body accepts the same number of values as the continuation of the body itself, and passes the values to that continuation. (A body may be in tail context, in which case the continuation of the final expression is the same as the continuation of the body itself.)