r7rs-small-texinfo

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

commit a4b6859b932ef42a30865acec9a538fa0d069abe
parent 84214dbef6a2c8c2cebdfe27bc6af66f5f78738f
Author: Yuval Langer <yuvallangerontheroad@gmail.com>
Date:   Sat, 27 Jan 2024 17:45:04 +0200

Add more chapters, sections, and subsections.

Diffstat:
Mdoc/r7rs-small/r7rs-small.texinfo | 2116++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 2115 insertions(+), 1 deletion(-)

diff --git a/doc/r7rs-small/r7rs-small.texinfo b/doc/r7rs-small/r7rs-small.texinfo @@ -78,132 +78,2246 @@ The report concludes with a list of references and an alphabetic index. @node Introduction @chapter Introduction +Introduction + +Programming languages should be designed not by piling feature on top of feature, but +by removing the weaknesses and restrictions that make additional features appear +necessary. Scheme demonstrates that a very small number of rules for forming +expressions, with no restrictions on how they are composed, suffice to form a practical +and efficient programming language that is flexible enough to support most of the major +programming paradigms in use today. + +Scheme was one of the first programming languages to incorporate first-class +procedures as in the lambda calculus, thereby proving the usefulness of static scope rules +and block structure in a dynamically typed language. Scheme was the first major dialect +of Lisp to distinguish procedures from lambda expressions and symbols, to use a single +lexical environment for all variables, and to evaluate the operator position of a procedure +call in the same way as an operand position. By relying entirely on procedure calls to +express iteration, Scheme emphasized the fact that tail-recursive procedure calls are +essentially GOTOs that pass arguments, thus allowing a programming style that is both +coherent and efficient. Scheme was the first widely used programming language to +embrace first-class escape procedures, from which all previously known sequential +control structures can be synthesized. A subsequent version of Scheme introduced the +concept of exact and inexact numbers, an extension of Common Lisp’s generic +arithmetic. More recently, Scheme became the first programming language to support +hygienic macros, which permit the syntax of a block-structured language to be extended +in a consistent and reliable manner. + +Background + +The first description of Scheme was written in 1975 [35]. A revised report [31] appeared in +1978, which described the evolution of the language as its MIT implementation was +upgraded to support an innovative compiler [32]. Three distinct projects began in 1981 +and 1982 to use variants of Scheme for courses at MIT, Yale, and Indiana University [27, +24, 14]. An introductory computer science textbook using Scheme was published in 1984 +[1]. + +As Scheme became more widespread, local dialects began to diverge until students and +researchers occasionally found it difficult to understand code written at other sites. +Fifteen representatives of the major implementations of Scheme therefore met in +October 1984 to work toward a better and more widely accepted standard for Scheme. +Their report, the RRRS [8], was published at MIT and Indiana University in the summer of +1985. Further revision took place in the spring of 1986, resulting in the R3RS [29]. Work in +the spring of 1988 resulted in R4RS [10], which became the basis for the IEEE Standard for +the Scheme Programming Language in 1991 [18]. In 1998, several additions to the IEEE +standard, including high-level hygienic macros, multiple return values, and eval, were +finalized as the R5RS [20]. + +In the fall of 2006, work began on a more ambitious standard, including many new +improvements and stricter requirements made in the interest of improved portability. The +resulting standard, the R6RS, was completed in August 2007 [33], and was organized as a +core language and set of mandatory standard libraries. Several new implementations of +Scheme conforming to it were created. However, most existing R5RS implementations +(even excluding those which are essentially unmaintained) did not adopt R6RS, or adopted +only selected parts of it. + +In consequence, the Scheme Steering Committee decided in August 2009 to divide the +standard into two separate but compatible languages — a “small” language, suitable for +educators, researchers, and users of embedded languages, focused on R5RS +compatibility, and a “large” language focused on the practical needs of mainstream +software development, intended to become a replacement for R6RS. The present report +describes the “small” language of that effort: therefore it cannot be considered in +isolation as the successor to R6RS. + +We intend this report to belong to the entire Scheme community, and so we grant +permission to copy it in whole or in part without fee. In particular, we encourage +implementers of Scheme to use this report as a starting point for manuals and other +documentation, modifying it as necessary. + +Acknowledgments + +We would like to thank the members of the Steering Committee, William Clinger, Marc +Feeley, Chris Hanson, Jonathan Rees, and Olin Shivers, for their support and guidance. + +This report is very much a community effort, and we’d like to thank everyone who +provided comments and feedback, including the following people: David Adler, Eli +Barzilay, Taylan Ulrich Bayırlı/Kammer, Marco Benelli, Pierpaolo Bernardi, Peter Bex, Per +Bothner, John Boyle, Taylor Campbell, Raffael Cavallaro, Ray Dillinger, Biep Durieux, +Sztefan Edwards, Helmut Eller, Justin Ethier, Jay Reynolds Freeman, Tony Garnock-Jones, +Alan Manuel Gloria, Steve Hafner, Sven Hartrumpf, Brian Harvey, Moritz Heidkamp, +Jean-Michel Hufflen, Aubrey Jaffer, Takashi Kato, Shiro Kawai, Richard Kelsey, Oleg +Kiselyov, Pjotr Kourzanov, Jonathan Kraut, Daniel Krueger, Christian Stigen Larsen, Noah +Lavine, Stephen Leach, Larry D. Lee, Kun Liang, Thomas Lord, Vincent Stewart Manis, Perry +Metzger, Michael Montague, Mikael More, Vitaly Magerya, Vincent Manis, Vassil Nikolov, +Joseph Wayne Norton, Yuki Okumura, Daichi Oohashi, Jeronimo Pellegrini, Jussi +Piitulainen, Alex Queiroz, Jim Rees, Grant Rettke, Andrew Robbins, Devon Schudy, Bakul +Shah, Robert Smith, Arthur Smyles, Michael Sperber, John David Stone, Jay Sulzberger, +Malcolm Tredinnick, Sam Tobin-Hochstadt, Andre van Tonder, Daniel Villeneuve, Denis +Washington, Alan Watson, Mark H. Weaver, Göran Weinholt, David A. Wheeler, Andy +Wingo, James Wise, Jörg F. Wittenberger, Kevin A. Wortman, Sascha Ziemann. + +In addition we would like to thank all the past editors, and the people who helped them in +turn: Hal Abelson, Norman Adams, David Bartley, Alan Bawden, Michael Blair, Gary +Brooks, George Carrette, Andy Cromarty, Pavel Curtis, Jeff Dalton, Olivier Danvy, Ken +Dickey, Bruce Duba, Robert Findler, Andy Freeman, Richard Gabriel, Yekta Gürsel, Ken +Haase, Robert Halstead, Robert Hieb, Paul Hudak, Morry Katz, Eugene Kohlbecker, Chris +Lindblad, Jacob Matthews, Mark Meyer, Jim Miller, Don Oxley, Jim Philbin, Kent Pitman, +John Ramsdell, Guillermo Rozas, Mike Shaff, Jonathan Shapiro, Guy Steele, Julie Sussman, +Perry Wagle, Mitchel Wand, Daniel Weise, Henry Wu, and Ozan Yigit. We thank Carol +Fessenden, Daniel Friedman, and Christopher Haynes for permission to use text from the +Scheme 311 version 4 reference manual. We thank Texas Instruments, Inc. for permission +to use text from the TI Scheme Language Reference Manual [37]. We gladly acknowledge the +influence of manuals for MIT Scheme [24], T [28], Scheme 84 [15], Common Lisp [34], and +Algol 60 [25], as well as the following SRFIs: 0, 1, 4, 6, 9, 11, 13, 16, 30, 34, 39, 43, 46, 62, and +87, all of which are available at http://srfi.schemers.org. + + @node Overview of Scheme @chapter Overview of Scheme @node Semantics @section Semantics +This section gives an overview of Scheme’s semantics. A detailed informal semantics is the +subject of chapters 3 through 6. For reference purposes, section 7.2 provides a formal +semantics of Scheme. + +Scheme is a statically scoped programming language. Each use of a variable is associated +with a lexically apparent binding of that variable. + +Scheme is a dynamically typed language. Types are associated with values (also called +objects) rather than with variables. Statically typed languages, by contrast, associate types +with variables and expressions as well as with values. + +All objects created in the course of a Scheme computation, including procedures and +continuations, have unlimited extent. No Scheme object is ever destroyed. The reason +that implementations of Scheme do not (usually!)​ ​run out of storage is that they are +permitted to reclaim the storage occupied by an object if they can prove that the object +cannot possibly matter to any future computation. Implementations of 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 procedure. Thus with a properly tail-recursive implementation, +iteration can be expressed using the ordinary procedure-call mechanics, so that special +iteration constructs are useful only as syntactic sugar. See section 3.5. + +Scheme procedures are objects in their own right. Procedures can be created +dynamically, stored in data structures, returned as results of procedures, and so on. One +distinguishing feature of 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 6.10. + +Arguments to Scheme procedures are always passed by value, which means that the +actual argument expressions are evaluated before the procedure gains control, +regardless of whether the procedure needs the result of the evaluation. 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 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. Exact +arithmetic is not limited to integers. + @node Syntax @section Syntax +Scheme, like most dialects of Lisp, employs a fully parenthesized prefix notation for +programs and other data; the grammar of Scheme generates a sublanguage of the +language used for data. An important consequence of this simple, uniform representation +is that Scheme programs and data can easily be treated uniformly by other Scheme +programs. For example, the eval procedure evaluates a Scheme program expressed as +data. + +The read procedure performs syntactic as well as lexical decomposition of the data it +reads. The read procedure parses its input as data (section 7.1.2), not as program. + +The formal syntax of Scheme is described in section 7.1. + @node Notation and terminology @section Notation and terminology @node Base and optional features @subsection Base and optional features +Every identifier defined in this report appears in one or more of several libraries. +Identifiers defined in the base library are not marked specially in the body of the report. +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 all the standard libraries and the identifiers they export +is given in Appendix A. + +All implementations of Scheme: + +* Must provide the base library and all the identifiers exported from it. + +* May provide or omit the other libraries given in this report, but each library must either + be provided in its entirety, exporting no additional identifiers, or else omitted + altogether. + +* May provide other libraries not described in this report. + +* May also extend the function of any identifier in this report, provided the extensions + are not in conflict with the language reported here. + +* Must support portable code by providing a mode of operation in which the lexical + syntax does not conflict with the lexical syntax described in this report. + @node Error situations and unspecified behavior @subsection 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. An error is signaled by +raising a non-continuable exception, as if by the procedure raise as described in section +6.11. The object raised is implementation-dependent and need not be distinct from +objects previously used for the same purpose. In addition to errors signaled in situations +described in this report, programmers can signal their own errors and handle signaled +errors. + +The phrase “an error that satisfies predicate is signaled” means that an error is signaled as +above. Furthermore, if the object that is signaled is passed to the specified predicate (such +as file-error? or read-error?), the predicate returns #t. + +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. Such a +situation is sometimes, but not always, referred to with the phrase “an error.” In such a +situation, an implementation may or may not signal an error; if it does signal an error, the +object that is signaled may or may not satisfy the predicates error-object?, file-error?, or +read-error?. Alternatively, implementations may provide non-portable extensions. + +For example, it is an error for a procedure to be passed an argument of a type that the +procedure is not explicitly specified to handle, even though such domain errors are seldom +mentioned in this report. Implementations may signal an error, extend a procedure’s +domain of definition to include such arguments, or fail catastrophically. + +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 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, or if an arithmetic operation would +produce an exact number that is too large for the implementation to represent. + +If the value of an expression is said to be “unspecified,” then the expression must evaluate +to some object without signaling an error, but the value depends on the implementation; +this report explicitly does not say what value is returned. + +Finally, the words and phrases “must,” “must not,” “shall,” “shall not,” “should,” “should +not,” “may,” “required,” “recommended,” and “optional,” although not capitalized in this +report, are to be interpreted as described in RFC 2119 [3]. They are used only with +reference to implementer or implementation behavior, not with reference to +programmer or program behavior. + @node Entry format @subsection Entry format + +Chapters 4 and 6 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 +procedure. An entry begins with one or more header lines of the form + +category: + +template + + +for identifiers in the base library, or + +name library + +category: + +template + + +where + +name is the short name of a library as defined in Appendix A. + +If + +category is “syntax,” 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 +<variable>. Syntactic variables are intended 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> <thing2> … + +indicates one or more occurrences of a <thing>. + +If + +category is “auxiliary syntax,” then the entry describes a syntax binding that occurs only as +part of specific surrounding expressions. Any use as an independent syntactic construct +or variable is an error. + +If + +category is “procedure,” then the entry describes a procedure, and the header line gives a +template for a call to the procedure. Argument names in the template are + +italicized. Thus the header line + +procedure: (vector-ref + +vector + +k) + + +indicates that the procedure bound to the vector-ref variable takes two arguments, a +vector + +vector and an exact non-negative integer + +k (see below). The header lines + +procedure: (make-vector + +k) + + +procedure: (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 a procedure 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, then it is an error if that argument is not of the named +type. For example, the header line for vector-ref given above dictates that the first +argument to vector-ref is a vector. The following naming conventions also imply type +restrictions: + + alist association list + (list of pairs) + boolean boolean value + (#t or #f) + byte exact integer 0 + ≤byte < 256 + bytevector bytevector + char character + end exact + non-negative + integer + k, exact + non-negative + k1, … integer + + kj, … + letter alphabetic + character + list, list (see section + 6.4) + list1, … + + listj, … + n, integer + + n1, … + + nj, … + obj any object + pair pair + port port + proc procedure + q, rational + number + q1, … + + qj, … + start exact + non-negative + integer + string string + symbol symbol + thunk zero-argument + procedure + vector vector + x, real number + + x1, … + + xj, … + y, real number + + y1, … + + yj, … + z, complex + number + z1, … + + zj, … + +The names + +start and + +end are used as indexes into strings, vectors, and bytevectors. Their use implies the +following: + +* It is an error if + + start is greater than + + end. + +* It is an error if + + end is greater than the length of the string, vector, or bytevector. + +* If + + start is omitted, it is assumed to be zero. + +* If + + end is omitted, it assumed to be the length of the string, vector, or bytevector. + +* The index + + start is always inclusive and the index + + end is always exclusive. As an example, consider a string. If + + start and + + end are the same, an empty substring is referred to, and if + + start is zero and + + end is the length of + + string, then the entire string is referred to. + @node Evaluation examples @subsection Evaluation examples +The symbol “⟹” used in program examples is 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 an +environment containing the base library, to an object that can be represented externally +by the sequence of characters “ 40.” See section 3.3 for a discussion of external +representations of objects. + @node Naming conventions @subsection Naming conventions +By convention, ? is the final character of the names of procedures that always return a +boolean value. Such procedures are called predicates. Predicates are generally understood +to be side-effect free, except that they may raise an exception when passed the wrong +type of argument. + +Similarly, ! is the final character of the names of procedures that store values into +previously allocated locations (see section 3.4). Such procedures are called mutation +procedures. The value returned by a mutation procedure is unspecified. + +By convention, “->” appears within the names of procedures 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. + +A command is a procedure that does not return useful values to its continuation. + +A thunk is a procedure that does not accept arguments. + @node Lexical conventions @chapter Lexical conventions +This section gives an informal account of some of the lexical conventions used in writing +Scheme programs. For a formal syntax of Scheme, see section 7.1. + @node Identifiers @section Identifiers +An identifieris any sequence of letters, digits, and “extended identifier characters” +provided that it does not have a prefix which is a valid number. However, the . token (a +single period) used in the list syntax is not an identifier. + +All implementations of Scheme must support the following extended identifier +characters: + +!​ ​$ % & * + - . / :​ ​< = > ? @ ^ _ ~ Alternatively, an identifier can be represented by a sequence +of zero or more characters enclosed within vertical lines (|), analogous to string literals. +Any character, including whitespace characters, but excluding the backslash and vertical +line characters, can appear verbatim in such an identifier. In addition, characters can be +specified using either an <inline hex escape> or the same escapes available in strings. + +For example, the identifier |H\x65;llo| is the same identifier as Hello, and in an +implementation that supports the appropriate Unicode character the identifier |\x3BB;| +is the same as the identifier λ. What is more, |\t\t| and |\x9;\x9;| are the same. Note +that || is a valid identifier that is different from any other identifier. + +Here are some examples of identifiers: + +... + ++soup+ <=? +->string a34kTMNs +lambda list->vector +q V17a +|two words| |two\x20;words| +the-word-recursion-has-many-meanings See section 7.1.1 for the formal syntax of +identifiers. + +Identifiers have two uses within Scheme programs: + +* Any identifier can be used as a variableor as a syntactic keyword(see sections 3.1 and + 4.3). + +* When an identifier appears as a literal or within a literal (see section 4.1.2), it is being + used to denote a symbol (see section 6.5). + +In contrast with earlier revisions of the report [20], the syntax distinguishes between +upper and lower case in identifiers and in characters specified using their names. +However, it does not distinguish between upper and lower case in numbers, nor in <inline +hex escapes> used in the syntax of identifiers, characters, or strings. None of the +identifiers defined in this report contain upper-case characters, even when they appear to +do so as a result of the English-language convention of capitalizing the first word of a +sentence. + +The following directives give explicit control over case folding. + +#!fold-case +#!no-fold-case + +These directives can appear anywhere comments are permitted (see section 2.2) but +must be followed by a delimiter. They are treated as comments, except that they affect +the reading of subsequent data from the same port. The #!fold-case directive causes +subsequent identifiers and character names to be case-folded as if by string-foldcase (see +section 6.7). It has no effect on character literals. The #!no-fold-case directive causes a +return to the default, non-folding behavior. + @node Whitespace and comments @section Whitespace and comments +Whitespace characters include the space, tab, and newline characters. (Implementations +may provide additional whitespace characters such as page break.) Whitespace is used +for improved readability and as necessary to separate tokens from each other, a token +being an indivisible lexical unit such as an identifier or number, but is otherwise +insignificant. Whitespace can occur between any two tokens, but not within a token. +Whitespace occurring inside a string or inside a symbol delimited by vertical lines is +significant. + +The lexical syntax includes several comment forms. Comments are treated exactly like +whitespace. + +A semicolon (;) indicates the start of a line comment.The comment continues to the end +of the line on which the semicolon appears. Another way to indicate a comment is to +prefix a <datum> (cf.​ ​section 7.1.2) with #;and optional <whitespace>. The comment +consists of the comment prefix #;, the space, and the <datum> together. This notation is +useful for “commenting out” sections of code. + +Block comments are indicated with properly nested #|and |# pairs. + +#| + The FACT procedure computes the factorial + of a non-negative integer. +|# +(define fact + (lambda (n) + (if (= n 0) + #;(= n 1) + 1 ;Base case: return 1 + (* n (fact (- n 1)))))) + @node Other notations @section Other notations +For a description of the notations used for numbers, see section 6.2. + +.​ ​+ - + These are used in numbers, and can also occur anywhere in an identifier. A delimited + plus or minus sign by itself is also an identifier. A delimited period (not occurring + within a number or identifier) is used in the notation for pairs (section 6.4), and to + indicate a rest-parameter in a formal parameter list (section 4.1.4). Note that a + sequence of two or more periods is an identifier. + +( ) + Parentheses are used for grouping and to notate lists (section 6.4). + +' + The apostrophe (single quote) character is used to indicate literal data (section + 4.1.2). + +` + The grave accent (backquote) character is used to indicate partly constant data + (section 4.2.8). + +, ,@ + The character comma and the sequence comma at-sign are used in conjunction with + quasiquotation (section 4.2.8). + +" + The quotation mark character is used to delimit strings (section 6.7). + +\ + Backslash is used in the syntax for character constants (section 6.6) and as an escape + character within string constants (section 6.7) and identifiers (section 7.1.1). + +[ ] { } | + Left and right square and curly brackets (braces) are reserved for possible future + extensions to the language. + +# + The number sign is used for a variety of purposes depending on the character that + immediately follows it: + +#t #f + These are the boolean constants (section 6.3), along with the alternatives #true and + #false. + +#\ + This introduces a character constant (section 6.6). + +#( + This introduces a vector constant (section 6.8). Vector constants are terminated by ) . + +#u8( + This introduces a bytevector constant (section 6.9). Bytevector constants are + terminated by ) . + +#e #i #b #o #d #x + These are used in the notation for numbers (section 6.2.5). + +#<n>= #<n># + These are used for labeling and referencing other literal data (section 2.4). + @node Datum labels @section Datum labels +lexical syntax: #<n>=<datum> +lexical syntax: #<n># + +The lexical syntax #<n>=<datum> reads the same as <datum>, but also results in <datum> +being labelled by <n>. It is an error if <n> is not a sequence of digits. + +The lexical syntax #<n># serves as a reference to some object labelled by #<n>=; the +result is the same object as the #<n>= (see section 6.1). Together, these syntaxes permit +the notation of structures with shared or circular substructure. + +(let ((x (list 'a 'b 'c))) + (set-cdr! (cddr x) x) + x) ⟹ #0=(a b c . #0#) +The scope of a datum label is the portion of the outermost datum in which it appears that +is to the right of the label. Consequently, a reference #<n># can occur only after a label +#<n>=; it is an error to attempt a forward reference. In addition, it is an error if the +reference appears as the labelled object itself (as in #<n>= #<n>#), because the object +labelled by #<n>= is not well defined in this case. + +It is an error for a <program> or <library> to include circular references except in literals. +In particular, it is an error for quasiquote (section 4.2.8) to contain them. + +#1=(begin (display #\x) #1#) + ⟹ error + @node Basic concepts @chapter Basic concepts @node Variables, syntactic keywords, and regions @section Variables, syntactic keywords, and regions +An identifiercan name either a type of syntax or a location where a value can be stored. An +identifier that names a type of syntax is called a syntactic keywordand is said to be bound to +a transformer for that syntax. An identifier that names a location is called a variableand is +said to be bound to that location. The set of all visible bindingsin effect at some point in a +program is known as the environment in effect at that point. The value stored in the +location to which a variable is bound is called the variable’s value. By abuse of +terminology, the variable is sometimes said to name the value or to be bound to the +value. This is not quite accurate, but confusion rarely results from this practice. + +Certain expression types are used to create new kinds of syntax and to bind syntactic +keywords to those new syntaxes, while other expression types create new locations and +bind variables to those locations. These expression types are called binding constructs. +Those that bind syntactic keywords are listed in section 4.3. The most fundamental of the +variable binding constructs is the lambda expression, because all other variable binding +constructs (except top-level bindings) can be explained in terms of lambda expressions. +The other variable binding constructs are let, let*, letrec, letrec*, let-values, let*-values, +and do expressions (see sections 4.1.4, 4.2.2, and 4.2.4). + +Scheme is a language with block structure. To each place where an identifier is bound in a +program there corresponds a region of the program text within which the binding is +visible. The region is determined by the particular binding construct that establishes the +binding; if the binding is established by a lambda expression, for example, then its region +is the entire lambda expression. Every mention of an identifier refers to the binding of the +identifier that established the innermost of the regions containing the use. If there is no +binding of the identifier whose region contains the use, then the use refers to the binding +for the variable in the global environment, if any (chapters 4 and 6); if there is no binding +for the identifier, it is said to be unbound. + @node Disjointness of types @section Disjointness of types +No object satisfies more than one of the following predicates: + +boolean? bytevector? +char? eof-object? +null? number? +pair? port? +procedure? string? +symbol? vector? +and all predicates created by define-record-type. + +These predicates define the types boolean, bytevector, character, the empty list object, +eof-object, number, pair, port, procedure, string, symbol, vector, and all record types. + +Although there is a separate boolean type, any Scheme value can be used as a boolean +value for the purpose of a conditional test. As explained in section 6.3, all values count as +true in such a test except for #f. This report uses the word “true” to refer to any Scheme +value except #f, and the word “false” to refer to #f. + @node External representations @section External representations +An important concept in Scheme (and Lisp) is that of the external representation of an +object as a sequence of characters. For example, an external representation of the +integer 28 is the sequence of characters “28”, and an external representation of a list +consisting of the integers 8 and 13 is the sequence of characters “(8 13)”. + +The external representation of an object is not necessarily unique. The integer 28 also has +representations “#e28.000” and “#x1c”, and the list in the previous paragraph also has the +representations “( 08 13 )” and “(8 .​ ​(13 .​ ​()))” (see section 6.4). + +Many objects have standard external representations, but some, such as procedures, do +not have standard representations (although particular implementations may define +representations for them). + +An external representation can be written in a program to obtain the corresponding +object (see quote, section 4.1.2). + +External representations can also be used for input and output. The procedure read +(section 6.13.2) parses external representations, and the procedure write (section 6.13.3) +generates them. Together, they provide an elegant and powerful input/output facility. + +Note that the sequence of characters “(+ 2 6)” is not an external representation of the +integer 8, even though it is an expression evaluating to the integer 8; rather, it is an +external representation of a three-element list, the elements of which are the symbol + +and the integers 2 and 6. Scheme’s syntax has the property that any sequence of +characters that is an expression is also the external representation of some object. This +can lead to confusion, since it is not always obvious out of context whether a given +sequence of characters is intended to denote data or program, but it is also a source of +power, since it facilitates writing programs such as interpreters and compilers that treat +programs as data (or vice versa). + +The syntax of external representations of various kinds of objects accompanies the +description of the primitives for manipulating the objects in the appropriate sections of +chapter 6. + @node Storage model @section Storage model +Variables and objects such as pairs, strings, vectors, and bytevectors implicitly denote +locationsor sequences of locations. A string, for example, denotes as many locations as +there are characters in the string. A new value can be stored into one of these locations +using the string-set! procedure, but the string continues to denote the same locations as +before. + +An object fetched from a location, by a variable reference or by a procedure such as car, +vector-ref, or string-ref, is equivalent in the sense of eqv? (section 6.1) to the object last +stored in the location before the fetch. + +Every location is marked to show whether it is in use. No variable or object ever refers to a +location that is not in use. + +Whenever this report speaks of storage being newly allocated for a variable or object, +what is meant is that an appropriate number of locations are chosen from the set of +locations that are not in use, and the chosen locations are marked to indicate that they +are now in use before the variable or object is made to denote them. Notwithstanding +this, it is understood that the empty list cannot be newly allocated, because it is a unique +object. It is also understood that empty strings, empty vectors, and empty bytevectors, +which contain no locations, may or may not be newly allocated. + +Every object that denotes locations is either mutableor immutable. Literal constants, the +strings returned by symbol->string, and possibly the environment returned by +scheme-report-environment are immutable objects. All objects created by the other +procedures listed in this report are mutable. It is an error to attempt to store a new value +into a location that is denoted by an immutable object. + +These locations are to be understood as conceptual, not physical. Hence, they do not +necessarily correspond to memory addresses, and even if they do, the memory address +might not be constant. + + Rationale: In many systems it is desirable for constants(i.e. the values of literal + expressions) to reside in read-only memory. Making it an error to alter constants + permits this implementation strategy, while not requiring other systems to + distinguish between mutable and immutable objects. + @node Proper tail recursion @section Proper tail recursion +Implementations of Scheme are required to be properly tail-recursive. Procedure calls that +occur in certain syntactic contexts defined below are tail calls. A Scheme implementation is +properly tail-recursive if it supports an unbounded number of active tail calls. A call is +active if the called procedure might still return. Note that this includes calls that might be +returned from either by the current continuation or by continuations captured earlier by +call-with-current-continuation that are later invoked. In the absence of captured +continuations, calls could return at most once and the active calls would be those that had +not yet returned. A formal definition of proper tail recursion can be found in [6]. + + Rationale: Intuitively, no space is needed for an active tail call because the + continuation that is used in the tail call has the same semantics as the continuation + passed to the procedure containing the call. Although an improper implementation + might use a new continuation in the call, a return to this new continuation would be + followed immediately by a return to the continuation passed to the procedure. A + properly tail-recursive implementation returns to that continuation directly. + + Proper tail recursion was one of the central ideas in Steele and Sussman’s original + version of Scheme. Their first Scheme interpreter implemented both functions and + actors. Control flow was expressed using actors, which differed from functions in + that they passed their results on to another actor instead of returning to a caller. In + the terminology of this section, each actor finished with a tail call to another actor. + + Steele and Sussman later observed that in their interpreter the code for dealing with + actors was identical to that for functions and thus there was no need to include both + in the language. + +A tail callis a procedure call that occurs in a tail context. Tail contexts are defined +inductively. Note that a tail context is always determined with respect to a particular +lambda expression. + +* The last expression within the body of a lambda expression, shown as <tail expression> + below, occurs in a tail context. The same is true of all the bodies of case-lambda + expressions. + + (lambda <formals> + <definition>* <expression>* <tail expression>) + (case-lambda (<formals> <tail body>)*) + +* If one of the following expressions is in a tail context, then the subexpressions shown + as <tail expression> are in a tail context. These were derived from rules in the grammar + given in chapter 7 by replacing some occurrences of <body> with <tail body>, some + occurrences of <expression> with <tail expression>, and some occurrences of + <sequence> with <tail sequence>. Only those rules that contain tail contexts are shown + here. + + (if <expression> <tail expression> <tail expression>) + (if <expression> <tail expression>) + (cond <cond clause>+) + (cond <cond clause>* (else <tail sequence>)) + (case <expression> + <case clause>+) + (case <expression> + <case clause>* + (else <tail sequence>)) + (and <expression>* <tail expression>) + (or <expression>* <tail expression>) + (when <test> <tail sequence>) + (unless <test> <tail sequence>) + (let (<binding spec>*) <tail body>) + (let <variable> (<binding spec>*) <tail body>) + (let* (<binding spec>*) <tail body>) + (letrec (<binding spec>*) <tail body>) + (letrec* (<binding spec>*) <tail body>) + (let-values (<mv binding spec>*) <tail body>) + (let*-values (<mv binding spec>*) <tail body>) + (let-syntax (<syntax spec>*) <tail body>) + (letrec-syntax (<syntax spec>*) <tail body>) + (begin <tail sequence>) + (do (<iteration spec>*) + (<test> <tail sequence>) + <expression>*) + where + <cond clause> ⟶(<test> <tail sequence>) + <case clause> ⟶((<datum>*) <tail sequence>) + <tail body> ⟶<definition>* <tail sequence> + <tail sequence> ⟶<expression>* <tail expression> + +* If a cond or case expression is in a tail context, and has a clause of the form + (<expression1> => <expression2>) then the (implied) call to the procedure that results + from the evaluation of <expression2> is in a tail context. <expression2> itself is not in a + tail context. + +Certain procedures defined in this report are also required to perform tail calls. The first +argument passed to apply and to call-with-current-continuation, and the second +argument passed to call-with-values, must be called via a tail call. Similarly, eval must +evaluate its first argument as if it were in tail position within the eval procedure. + +In the following example the only tail call is the call to f. None of the calls to g or h are tail +calls. The reference to x is in a tail context, but it is not a call and thus is not a tail call. + +(lambda () + (if (g) + (let ((x (h))) + x) + (and (g) (f)))) + + Note: Implementations may recognize that some non-tail calls, such as the call to h + above, can be evaluated as though they were tail calls. In the example above, the let + expression could be compiled as a tail call to h. (The possibility of h returning an + unexpected number of values can be ignored, because in that case the effect of the + let is explicitly unspecified and implementation-dependent.) + @node Expressions @chapter Expressions +Expression types are categorized as primitive or derived. Primitive expression types include +variables and procedure calls. Derived expression types are not semantically primitive, +but can instead be defined as macros. Suitable syntax definitions of some of the derived +expressions are given in section 7.3. + +The procedures force, promise?, make-promise, and make-parameter are also described +in this chapter because they are intimately associated with the delay, delay-force, and +parameterize expression types. + @node Primitive expression types @section Primitive expression types @node Variable references @subsection Variable references +syntax: <variable> + +An expression consisting of a variable(section 3.1) is a variable reference. The value of the +variable reference is the value stored in the location to which the variable is bound. It is an +error to reference an unboundvariable. + +(define x 28) +x ⟹ 28 + @node Literal expressions @subsection Literal expressions +syntax: (quote <datum>) +syntax: '<datum> +syntax: <constant> + +(quote <datum>) evaluates to <datum>.<Datum> can be any external representation of a +Scheme object (see section 3.3). This notation is used to include literal constants in +Scheme code. + +(quote a) ⟹ a +(quote #(a b c)) ⟹ #(a b c) +(quote (+ 1 2)) ⟹ (+ 1 2) (quote <datum>) can be abbreviated as '<datum>. The two +notations are equivalent in all respects. + +'a ⟹ a +'#(a b c) ⟹ #(a b c) +'() ⟹ () +'(+ 1 2) ⟹ (+ 1 2) +'(quote a) ⟹ (quote a) +''a ⟹ (quote a) Numerical constants, string constants, character constants, +vector constants, bytevector constants, and boolean constants evaluate to themselves; +they need not be quoted. + +'145932 ⟹ 145932 +145932 ⟹ 145932 +'"abc" ⟹ "abc" +"abc" ⟹ "abc" +'#\a ⟹ #\a +#\a ⟹ #\a +'#(a 10) ⟹ #(a 10) +#(a 10) ⟹ #(a 10) +'#u8(64 65) ⟹ #u8(64 65) +#u8(64 65) ⟹ #u8(64 65) +'#t ⟹ #t +#t ⟹ #t As noted in section 3.4, it is an error to attempt to alter a constant (i.e. the value +of a literal expression) using a mutation procedure like set-car!​ ​or string-set!. + @node Procedure calls @subsection Procedure calls +syntax: (<operator> <operand1> …) + +A procedure call is written by enclosing in parentheses an expression for the procedure to +be called followed by expressions for the arguments to be passed to it. The operator and +operand expressions are evaluated (in an unspecified order) and the resulting procedure +is passed the resulting arguments. + +(+ 3 4) ⟹ 7 +((if #f + *) 3 4) ⟹ 12 The procedures in this document are available as the values of +variables exported by the standard libraries. For example, the addition and multiplication +procedures in the above examples are the values of the variables + and * in the base +library. New procedures are created by evaluating lambda expressions (see section 4.1.4). + +Procedure calls can return any number of values (see values in section 6.10). Most of the +procedures defined in this report return one value or, for procedures such as apply, pass +on the values returned by a call to one of their arguments. Exceptions are noted in the +individual descriptions. + + Note: In contrast to other dialects of Lisp, the order of evaluation is unspecified, and + the operator expression and the operand expressions are always evaluated with the + same evaluation rules. + + Note: Although the order of evaluation is otherwise unspecified, the effect of any + concurrent evaluation of the operator and operand expressions is constrained to be + consistent with some sequential order of evaluation. The order of evaluation may be + chosen differently for each procedure call. + + Note: In many dialects of Lisp, the empty list, (), is a legitimate expression evaluating + to itself. In Scheme, it is an error. + @node Procedures @subsection Procedures +syntax: (lambda <formals> <body>) + +Syntax: <Formals> is a formal arguments list as described below, and <body> is a sequence +of zero or more definitions followed by one or more expressions. + +Semantics: A lambda expression evaluates to a procedure. The environment in effect when +the lambda expression was evaluated is remembered as part of the procedure. When the +procedure is later called with some actual arguments, the environment in which the +lambda expression was evaluated will be extended by binding the variables in the formal +argument list to fresh locations, and the corresponding actual argument values will be +stored in those locations. (A fresh location is one that is distinct from every previously +existing location.) Next, the expressions in the body of the lambda expression (which, if it +contains definitions, represents a letrec* form — see section 4.2.2) will be evaluated +sequentially in the extended environment. The results of the last expression in the body +will be returned as the results of the procedure call. + +(lambda (x) (+ x x)) ⟹ a procedure +((lambda (x) (+ x x)) 4) ⟹ 8 + +(define reverse-subtract + (lambda (x y) (- y x))) +(reverse-subtract 7 10) ⟹ 3 + +(define add4 + (let ((x 4)) + (lambda (y) (+ x y)))) +(add4 6) ⟹ 10 <Formals> have one of the following forms: + +* (<variable1> …): The procedure takes a fixed number of arguments; when the + procedure is called, the arguments will be stored in fresh locations that are bound to + the corresponding variables. + +* <variable>: The procedure takes any number of arguments; when the procedure is + called, the sequence of actual arguments is converted into a newly allocated list, and + the list is stored in a fresh location that is bound to <variable>. + +* (<variable1> … <variablen>​ ​. <variablen+1>): If a space-delimited period precedes the last + variable, then the procedure takes n or more arguments, where n is the number of + formal arguments before the period (it is an error if there is not at least one). The value + stored in the binding of the last variable will be a newly allocated list of the actual + arguments left over after all the other actual arguments have been matched up against + the other formal arguments. + +It is an error for a <variable> to appear more than once in <formals>. + +((lambda x x) 3 4 5 6) ⟹ (3 4 5 6) +((lambda (x y . z) z) + 3 4 5 6) ⟹ (5 6) + +Each procedure created as the result of evaluating a lambda expression is (conceptually) +tagged with a storage location, in order to make eqv? and eq? work on procedures (see +section 6.1). + @node Conditionals @subsection Conditionals +syntax: (if <test> <consequent> <alternate>) +syntax: (if <test> <consequent>) + +Syntax: <Test>, <consequent>, and <alternate> are expressions. + +Semantics: An if expression is evaluated as follows: first, <test> is evaluated. If it yields a +true value(see section 6.3), then <consequent> is evaluated and its values are returned. +Otherwise <alternate> is evaluated and its values are returned. If <test> yields a false +value and no <alternate> is specified, then the result of the expression is unspecified. + +(if (> 3 2) 'yes 'no) ⟹ yes +(if (> 2 3) 'yes 'no) ⟹ no +(if (> 3 2) + (- 3 2) + (+ 3 2)) ⟹ 1 + @node Assignments @subsection Assignments +syntax: (set! <variable> <expression>) + +Semantics: <Expression> is evaluated, and the resulting value is stored in the location to +which <variable> is bound. It is an error if <variable> is not bound either in some +regionenclosing the set!​ ​expression or else globally. The result of the set! expression is +unspecified. + +(define x 2) +(+ x 1) ⟹ 3 +(set! x 4) ⟹ unspecified +(+ x 1) ⟹ 5 + @node Inclusion @subsection Inclusion +syntax: (include <string1> <string2> …) +syntax: (include-ci <string1> <string2> …) +Semantics: Both include and include-ci take one or more filenames expressed as string +literals, apply an implementation-specific algorithm to find corresponding files, read the +contents of the files in the specified order as if by repeated applications of read, and +effectively replace the include or include-ci expression with a begin expression containing +what was read from the files. The difference between the two is that include-ci reads each +file as if it began with the #!fold-case directive, while include does not. - + Note: Implementations are encouraged to search for files in the directory which + contains the including file, and to provide a way for users to specify other directories + to search. @node Derived expression types @section Derived expression types + +The constructs in this section are hygienic, as discussed in section 4.3. For reference +purposes, section 7.3 gives syntax definitions that will convert most of the constructs +described in this section into the primitive constructs described in the previous section. + @node Conditionals @subsection Conditionals + +syntax: (cond <clause1> <clause2> …) +auxiliary syntax: else +auxiliary syntax: => + +Syntax: <Clauses> take one of two forms, either + +(<test> <expression1> …)where <test> is any expression, or (<test> => <expression>)The +last <clause> can be an “else clause,” which has the form (else <expression1> +<expression2> …). + +Semantics: A cond expression is evaluated by evaluating the <test> expressions of +successive <clause>s in order until one of them evaluates to a true value(see section 6.3). +When a <test> evaluates to a true value, the remaining <expression>s in its <clause> are +evaluated in order, and the results of the last <expression> in the <clause> are returned +as the results of the entire cond expression. + +If the selected <clause> contains only the <test> and no <expression>s, then the value of +the <test> is returned as the result. If the selected <clause> uses the => alternate form, +then the <expression> is evaluated. It is an error if its value is not a procedure that +accepts one argument. This procedure is then called on the value of the <test> and the +values returned by this procedure are returned by the cond expression. + +If all <test>s evaluate to #f, and there is no else clause, then the result of the conditional +expression is unspecified; if there is an else clause, then its <expression>s are evaluated in +order, and the values of the last one are returned. + +(cond ((> 3 2) 'greater) + ((< 3 2) 'less)) ⟹ greater + +(cond ((> 3 3) 'greater) + ((< 3 3) 'less) + (else 'equal)) ⟹ equal + +(cond ((assv 'b '((a 1) (b 2))) => cadr) + (else #f)) ⟹ 2 + +syntax: (case <key> <clause1> <clause2> …) + +Syntax: <Key> can be any expression. Each <clause> has the form + +((<datum1> …) <expression1> <expression2> …),where each <datum> is an external +representation of some object. It is an error if any of the <datum>s are the same +anywhere in the expression. Alternatively, a <clause> can be of the form ((<datum1> …) => +<expression>)The last <clause> can be an “else clause,” which has one of the forms (else +<expression1> <expression2> …) +or (else => <expression>). + +Semantics: A case expression is evaluated as follows. <Key> is evaluated and its result is +compared against each <datum>. If the result of evaluating <key> is the same (in the +sense of eqv?; see section 6.1) to a <datum>, then the expressions in the corresponding +<clause> are evaluated in order and the results of the last expression in the <clause> are +returned as the results of the case expression. + +If the result of evaluating <key> is different from every <datum>, then if there is an else +clause, its expressions are evaluated and the results of the last are the results of the case +expression; otherwise the result of the case expression is unspecified. + +If the selected <clause> or else clause uses the => alternate form, then the <expression> is +evaluated. It is an error if its value is not a procedure accepting one argument. This +procedure is then called on the value of the <key> and the values returned by this +procedure are returned by the case expression. + +(case (* 2 3) + ((2 3 5 7) 'prime) + ((1 4 6 8 9) 'composite)) ⟹ composite +(case (car '(c d)) + ((a) 'a) + ((b) 'b)) ⟹ unspecified +(case (car '(c d)) + ((a e i o u) 'vowel) + ((w y) 'semivowel) + (else => (lambda (x) x))) ⟹ c + +syntax: (and <test1> …) + +Semantics: The <test> expressions are evaluated from left to right, and if any expression +evaluates to #f (see section 6.3), then #f is returned. Any remaining expressions are not +evaluated. If all the expressions evaluate to true values, the values of the last expression +are returned. If there are no expressions, then #t is returned. + +(and (= 2 2) (> 2 1)) ⟹ #t +(and (= 2 2) (< 2 1)) ⟹ #f +(and 1 2 'c '(f g)) ⟹ (f g) +(and) ⟹ #t + +syntax: (or <test1> …) + +Semantics: The <test> expressions are evaluated from left to right, and the value of the +first expression that evaluates to a true value (see section 6.3) is returned. Any remaining +expressions are not evaluated. If all expressions evaluate to #f or if there are no +expressions, then #f is returned. + +(or (= 2 2) (> 2 1)) ⟹ #t +(or (= 2 2) (< 2 1)) ⟹ #t +(or #f #f #f) ⟹ #f +(or (memq 'b '(a b c)) + (/ 3 0)) ⟹ (b c) + +syntax: (when <test> <expression1> <expression2> …) + +Syntax: The <test> is an expression. + +Semantics: The test is evaluated, and if it evaluates to a true value, the expressions are +evaluated in order. The result of the when expression is unspecified. + +(when (= 1 1.0) + (display "1") + (display "2")) ⟹ unspecified + and prints 12 + +syntax: (unless <test> <expression1> <expression2> …) + +Syntax: The <test> is an expression. + +Semantics: The test is evaluated, and if it evaluates to #f, the expressions are evaluated in +order. The result of the unless expression is unspecified. + +(unless (= 1 1.0) + (display "1") + (display "2")) ⟹ unspecified + and prints nothing + +syntax: (cond-expand <ce-clause1> <ce-clause2> …) + +Syntax: The cond-expand expression type provides a way to statically expand different +expressions depending on the implementation. A <ce-clause> takes the following form: + +(<feature requirement> <expression> …) + +The last clause can be an “else clause,” which has the form + +(else <expression> …) + +A <feature requirement> takes one of the following forms: + +* <feature identifier> + +* (library <library name>) + +* (and <feature requirement> …) + +* (or <feature requirement> …) + +* (not <feature requirement>) + +Semantics: Each implementation maintains a list of feature identifiers which are present, +as well as a list of libraries which can be imported. The value of a <feature requirement> is +determined by replacing each <feature identifier> and (library <library name>) on the +implementation’s lists with #t, and all other feature identifiers and library names with #f, +then evaluating the resulting expression as a Scheme boolean expression under the +normal interpretation of and, or, and not. + +A cond-expand is then expanded by evaluating the <feature requirement>s of successive +<ce-clause>s in order until one of them returns #t. When a true clause is found, the +corresponding <expression>s are expanded to a begin, and the remaining clauses are +ignored. If none of the <feature requirement>s evaluate to #t, then if there is an else +clause, its <expression>s are included. Otherwise, the behavior of the cond-expand is +unspecified. Unlike cond, cond-expand does not depend on the value of any variables. + +The exact features provided are implementation-defined, but for portability a core set of +features is given in appendix B. + @node Binding constructs @subsection Binding constructs + +The binding constructs let, let*, letrec, letrec*, let-values, and let*-values give Scheme a +block structure, like Algol 60. The syntax of the first four constructs is identical, but they +differ in the regionsthey establish for their variable bindings. In a let expression, the +initial values are computed before any of the variables become bound; in a let* +expression, the bindings and evaluations are performed sequentially; while in letrec and +letrec* expressions, all the bindings are in effect while their initial values are being +computed, thus allowing mutually recursive definitions. The let-values and let*-values +constructs are analogous to let and let* respectively, but are designed to handle +multiple-valued expressions, binding different identifiers to the returned values. + +syntax: (let <bindings> <body>) + +Syntax: <Bindings> has the form + +((<variable1> <init1>) …),where each <init> is an expression, and <body> is a sequence of +zero or more definitions followed by a sequence of one or more expressions as described +in section 4.1.4. It is an error for a <variable> to appear more than once in the list of +variables being bound. + +Semantics: The <init>s are evaluated in the current environment (in some unspecified +order), the <variable>s are bound to fresh locations holding the results, the <body> is +evaluated in the extended environment, and the values of the last expression of <body> +are returned. Each binding of a <variable> has <body> as its region. + +(let ((x 2) (y 3)) + (* x y)) ⟹ 6 + +(let ((x 2) (y 3)) + (let ((x 7) + (z (+ x y))) + (* z x))) ⟹ 35 See also “named let,” section 4.2.4. + +syntax: (let* <bindings> <body>) + +Syntax: <Bindings> has the form + +((<variable1> <init1>) …),and <body> is a sequence of zero or more definitions followed by +one or more expressions as described in section 4.1.4. + +Semantics: The let* binding construct is similar to let, but the bindings are performed +sequentially from left to right, and the regionof a binding indicated by (<variable> <init>) +is that part of the let* expression to the right of the binding. Thus the second binding is +done in an environment in which the first binding is visible, and so on. The <variable>s +need not be distinct. + +(let ((x 2) (y 3)) + (let* ((x 7) + (z (+ x y))) + (* z x))) ⟹ 70 + +syntax: (letrec <bindings> <body>) + +Syntax: <Bindings> has the form + +((<variable1> <init1>) …),and <body> is a sequence of zero or more definitions followed by +one or more expressions as described in section 4.1.4. It is an error for a <variable> to +appear more than once in the list of variables being bound. + +Semantics: The <variable>s are bound to fresh locations holding unspecified values, the +<init>s are evaluated in the resulting environment (in some unspecified order), each +<variable> is assigned to the result of the corresponding <init>, the <body> is evaluated in +the resulting environment, and the values of the last expression in <body> are returned. +Each binding of a <variable> has the entire letrec expression as its region, making it +possible to define mutually recursive procedures. + +(letrec ((even? + (lambda (n) + (if (zero? n) + #t + (odd? (- n 1))))) + (odd? + (lambda (n) + (if (zero? n) + #f + (even? (- n 1)))))) + (even? 88)) +⟹ #t One restriction on letrec is very important: if it is not possible to evaluate each <init> +without assigning or referring to the value of any <variable>, it is an error. The restriction +is necessary because letrec is defined in terms of a procedure call where a lambda +expression binds the <variable>s to the values of the <init>s. In the most common uses of +letrec, all the <init>s are lambda expressions and the restriction is satisfied automatically. + +syntax: (letrec* <bindings> <body>) + +Syntax: <Bindings> has the form + +((<variable1> <init1>) …),and <body>is a sequence of zero or more definitions followed by +one or more expressions as described in section 4.1.4. It is an error for a <variable> to +appear more than once in the list of variables being bound. + +Semantics: The <variable>s are bound to fresh locations, each <variable> is assigned in +left-to-right order to the result of evaluating the corresponding <init> (interleaving +evaluations and assignments), the <body> is evaluated in the resulting environment, and +the values of the last expression in <body> are returned. Despite the left-to-right +evaluation and assignment order, each binding of a <variable> has the entire letrec* +expression as its region, making it possible to define mutually recursive procedures. + +If it is not possible to evaluate each <init> without assigning or referring to the value of +the corresponding <variable> or the <variable> of any of the bindings that follow it in +<bindings>, it is an error. Another restriction is that it is an error to invoke the +continuation of an <init> more than once. + +;; Returns the arithmetic, geometric, and +;; harmonic means of a nested list of numbers +(define (means ton) + (letrec* + ((mean + (lambda (f g) + (f (/ (sum g ton) n)))) + (sum + (lambda (g ton) + (if (null? ton) + (+) + (if (number? ton) + (g ton) + (+ (sum g (car ton)) + (sum g (cdr ton))))))) + (n (sum (lambda (x) 1) ton))) + (values (mean values values) + (mean exp log) + (mean / /)))) +Evaluating (means '(3 (1 4))) returns three values: 8/3, 2.28942848510666 (approximately), +and 36/19. + +syntax: (let-values <mv binding spec> <body>) + +Syntax: <Mv binding spec> has the form + +((<formals1> <init1>) …), where each <init> is an expression, and <body> is zero or more +definitions followed by a sequence of one or more expressions as described in section +4.1.4. It is an error for a variable to appear more than once in the set of <formals>. + +Semantics: The <init>s are evaluated in the current environment (in some unspecified +order) as if by invoking call-with-values, and the variables occurring in the <formals> are +bound to fresh locations holding the values returned by the <init>s, where the <formals> +are matched to the return values in the same way that the <formals> in a lambda +expression are matched to the arguments in a procedure call. Then, the <body> is +evaluated in the extended environment, and the values of the last expression of <body> +are returned. Each binding of a <variable> has <body> as its region. + +It is an error if the <formals> do not match the number of values returned by the +corresponding <init>. + +(let-values (((root rem) (exact-integer-sqrt 32))) + (* root rem)) ⟹ 35 + +syntax: (let*-values <mv binding spec> <body>) + +Syntax: <Mv binding spec> has the form + +((<formals> <init>) …),and <body> is a sequence of zero or more definitions followed by +one or more expressions as described in section 4.1.4. In each <formals>, it is an error if +any variable appears more than once. + +Semantics: The let*-values construct is similar to let-values, but the <init>s are evaluated +and bindings created sequentially from left to right, with the region of the bindings of +each <formals> including the <init>s to its right as well as <body>. Thus the second <init> +is evaluated in an environment in which the first set of bindings is visible and initialized, +and so on. + +(let ((a 'a) (b 'b) (x 'x) (y 'y)) + (let*-values (((a b) (values x y)) + ((x y) (values a b))) + (list a b x y))) ⟹ (x y x y) + @node Sequencing @subsection Sequencing + +Both of Scheme’s sequencing constructs are named begin, but the two have slightly +different forms and uses: + +syntax: (begin <expression or definition> …) + +This form of begin can appear as part of a <body>, or at the outermost level of a +<program>, or at the REPL, or directly nested in a begin that is itself of this form. It causes +the contained expressions and definitions to be evaluated exactly as if the enclosing begin +construct were not present. + + Rationale: This form is commonly used in the output of macros (see section 4.3) which + need to generate multiple definitions and splice them into the context in which they + are expanded. + +syntax: (begin <expression1> <expression2> …) + +This form of begin can be used as an ordinary expression. The <expression>s are +evaluated sequentially from left to right, and the values of the last <expression> are +returned. This expression type is used to sequence side effects such as assignments or +input and output. + +(define x 0) + +(and (= x 0) + (begin (set! x 5) + (+ x 1))) ⟹ 6 + +(begin (display "4 plus 1 equals ") + (display (+ 4 1))) ⟹ unspecified + and prints 4 plus 1 equals 5 + +Note that there is a third form of begin used as a library declaration: see section 5.6.1. + @node Iteration @subsection Iteration + +syntax: (do ((<variable1> <init1> <step1>) +…) +(<test> <expression> …) +<command> …) + +Syntax: All of <init>, <step>, <test>, and <command> are expressions. + +Semantics: A do expression is an iteration construct. It specifies a set of variables to be +bound, how they are to be initialized at the start, and how they are to be updated on each +iteration. When a termination condition is met, the loop exits after evaluating the +<expression>s. + +A do expression is evaluated as follows: The <init> expressions are evaluated (in some +unspecified order), the <variable>s are bound to fresh locations, the results of the <init> +expressions are stored in the bindings of the <variable>s, and then the iteration phase +begins. + +Each iteration begins by evaluating <test>; if the result is false (see section 6.3), then the +<command> expressions are evaluated in order for effect, the <step> expressions are +evaluated in some unspecified order, the <variable>s are bound to fresh locations, the +results of the <step>s are stored in the bindings of the <variable>s, and the next iteration +begins. + +If <test> evaluates to a true value, then the <expression>s are evaluated from left to right +and the values of the last <expression> are returned. If no <expression>s are present, +then the value of the do expression is unspecified. + +The regionof the binding of a <variable> consists of the entire do expression except for +the <init>s. It is an error for a <variable> to appear more than once in the list of do +variables. + +A <step> can be omitted, in which case the effect is the same as if (<variable> <init> +<variable>) had been written instead of (<variable> <init>). + +(do ((vec (make-vector 5)) + (i 0 (+ i 1))) + ((= i 5) vec) + (vector-set! vec i i)) ⟹ #(0 1 2 3 4) + +(let ((x '(1 3 5 7 9))) + (do ((x x (cdr x)) + (sum 0 (+ sum (car x)))) + ((null? x) sum))) ⟹ 25 + +syntax: (let <variable> <bindings> <body>) + +Semantics: “Named let” is a variant on the syntax of let which provides a more general +looping construct than do and can also be used to express recursion. It has the same +syntax and semantics as ordinary let except that <variable> is bound within <body> to a +procedure whose formal arguments are the bound variables and whose body is <body>. +Thus the execution of <body> can be repeated by invoking the procedure named by +<variable>. + +(let loop ((numbers '(3 -2 1 6 -5)) + (nonneg '()) + (neg '())) + (cond ((null? numbers) (list nonneg neg)) + ((>= (car numbers) 0) + (loop (cdr numbers) + (cons (car numbers) nonneg) + neg)) + ((< (car numbers) 0) + (loop (cdr numbers) + nonneg + (cons (car numbers) neg))))) +⟹ ((6 1 3) (-5 -2)) + @node Delayed evaluation @subsection Delayed evaluation + +lazy library syntax: (delay <expression>) + +Semantics: The delay construct is used together with the procedure force to implement +lazy evaluation or call by need. (delay <expression>) returns an object called a promise which +at some point in the future can be asked (by the force procedure) to evaluate +<expression>, and deliver the resulting value. The effect of <expression> returning +multiple values is unspecified. + +lazy library syntax: (delay-force <expression>) + +Semantics: The expression (delay-force + +expression) is conceptually similar to (delay (force + +expression)), with the difference that forcing the result of delay-force will in effect result in +a tail call to (force + +expression), while forcing the result of (delay (force + +expression)) might not. Thus iterative lazy algorithms that might result in a long series of +chains of delay and force can be rewritten using delay-force to prevent consuming +unbounded space during evaluation. + +lazy library procedure: (force promise) + +The force procedure forces the value of a + +promise created by delay, delay-force, or make-promise.If no value has been computed for +the promise, then a value is computed and returned. The value of the promise must be +cached (or “memoized”) so that if it is forced a second time, the previously computed +value is returned. Consequently, a delayed expression is evaluated using the parameter +values and exception handler of the call to force which first requested its value. If + +promise is not a promise, it may be returned unchanged. + +(force (delay (+ 1 2))) ⟹ 3 +(let ((p (delay (+ 1 2)))) + (list (force p) (force p))) + ⟹ (3 3) + +(define integers + (letrec ((next + (lambda (n) + (delay (cons n (next (+ n 1))))))) + (next 0))) +(define head + (lambda (stream) (car (force stream)))) +(define tail + (lambda (stream) (cdr (force stream)))) + +(head (tail (tail integers))) + ⟹ 2 The following example is a mechanical transformation of a lazy +stream-filtering algorithm into Scheme. Each call to a constructor is wrapped in delay, and +each argument passed to a deconstructor is wrapped in force. The use of (delay-force ...) +instead of (delay (force ...)) around the body of the procedure ensures that an +ever-growing sequence of pending promises does not exhaust available storage, because +force will in effect force such sequences iteratively. + +(define (stream-filter p? s) + (delay-force + (if (null? (force s)) + (delay '()) + (let ((h (car (force s))) + (t (cdr (force s)))) + (if (p? h) + (delay (cons h (stream-filter p? t))) + (stream-filter p? t)))))) + +(head (tail (tail (stream-filter odd? integers)))) + ⟹ 5 The following examples are not intended to illustrate good +programming style, as delay, force, and delay-force are mainly intended for programs +written in the functional style. However, they do illustrate the property that only one value +is computed for a promise, no matter how many times it is forced. + +(define count 0) +(define p + (delay (begin (set! count (+ count 1)) + (if (> count x) + count + (force p))))) +(define x 5) +p ⟹ a promise +(force p) ⟹ 6 +p ⟹ a promise, still +(begin (set! x 10) + (force p)) ⟹ 6 Various extensions to this semantics of delay, force and delay-force +are supported in some implementations: + +* Calling force on an object that is not a promise may simply return the object. + +* It may be the case that there is no means by which a promise can be operationally + distinguished from its forced value. That is, expressions like the following may evaluate + to either #t or to #f, depending on the implementation: + + (eqv? (delay 1) 1) ⟹ unspecified + (pair? (delay (cons 1 2))) ⟹ unspecified +* Implementations may implement “implicit forcing,” where the value of a promise is + forced by procedures that operate only on arguments of a certain type, like cdr and *. + However, procedures that operate uniformly on their arguments, like list, must not + force them. + + (+ (delay (* 3 7)) 13) ⟹ unspecified + (car + (list (delay (* 3 7)) 13)) ⟹ a promise + +lazy library procedure: (promise? + +obj) + + +The promise? procedure returns #t if its argument is a promise, and #f otherwise. Note +that promises are not necessarily disjoint from other Scheme types such as procedures. + +lazy library procedure: (make-promise + +obj) + + +The make-promise procedure returns a promise which, when forced, will return + +obj. It is similar to delay, but does not delay its argument: it is a procedure rather than +syntax. If + +obj is already a promise, it is returned. + @node Dynamic bindings @subsection Dynamic bindings + +The dynamic extent of a procedure call is the time between when it is initiated and when it +returns. In Scheme, call-with-current-continuation (section 6.10) allows reentering a +dynamic extent after its procedure call has returned. Thus, the dynamic extent of a call +might not be a single, continuous time period. + +This sections introduces parameter objects, which can be bound to new values for the +duration of a dynamic extent. The set of all parameter bindings at a given time is called +the dynamic environment. + +procedure: (make-parameter init) +procedure: (make-parameter init converter) + +Returns a newly allocated parameter object, which is a procedure that accepts zero +arguments and returns the value associated with the parameter object. Initially, this value +is the value of ( + +converter + +init), or of + +init if the conversion procedure + +converter is not specified. The associated value can be temporarily changed using +parameterize, which is described below. + +The effect of passing arguments to a parameter object is implementation-dependent. + +syntax: (parameterize ((<param1> <value1>) …) + <body>) + +Syntax: Both <param1> and <value1> are expressions. + +It is an error if the value of any <param> expression is not a parameter object. + +Semantics: A parameterize expression is used to change the values returned by specified +parameter objects during the evaluation of the body. + +The <param> and <value> expressions are evaluated in an unspecified order. The <body> +is evaluated in a dynamic environment in which calls to the parameters return the results +of passing the corresponding values to the conversion procedure specified when the +parameters were created. Then the previous values of the parameters are restored +without passing them to the conversion procedure. The results of the last expression in +the <body> are returned as the results of the entire parameterize expression. + + Note: If the conversion procedure is not idempotent, the results of (parameterize ((x + (x))) ...), which appears to bind the parameter + + x to its current value, might not be what the user expects. + +If an implementation supports multiple threads of execution, then parameterize must not +change the associated values of any parameters in any thread other than the current +thread and threads created inside <body>. + +Parameter objects can be used to specify configurable settings for a computation +without the need to pass the value to every procedure in the call chain explicitly. + +(define radix + (make-parameter + 10 + (lambda (x) + (if (and (exact-integer? x) (<= 2 x 16)) + x + (error "invalid radix"))))) + +(define (f n) (number->string n (radix))) + +(f 12) ⟹ "12" +(parameterize ((radix 2)) + (f 12)) ⟹ "1100" +(f 12) ⟹ "12" + +(radix 16) ⟹ unspecified + +(parameterize ((radix 0)) + (f 12)) ⟹ error + @node Exception handling @subsection Exception handling + +syntax: (guard (<variable> + <cond clause1> <cond clause2> …) + <body>) + +Syntax: Each <cond clause> is as in the specification of cond. + +Semantics: The <body> is evaluated with an exception handler that binds the raised object +(see raise in section 6.11) to <variable> and, within the scope of that binding, evaluates the +clauses as if they were the clauses of a cond expression. That implicit cond expression is +evaluated with the continuation and dynamic environment of the guard expression. If +every <cond clause>’s <test> evaluates to #f and there is no else clause, then +raise-continuable is invoked on the raised object within the dynamic environment of the +original call to raise or raise-continuable, except that the current exception handler is that +of the guard expression. + +See section 6.11 for a more complete discussion of exceptions. + +(guard (condition + ((assq 'a condition) => cdr) + ((assq 'b condition))) + (raise (list (cons 'a 42)))) +⟹ 42 + +(guard (condition + ((assq 'a condition) => cdr) + ((assq 'b condition))) + (raise (list (cons 'b 23)))) +⟹ (b . 23) + @node Quasiquotation @subsection Quasiquotation + +syntax: (quasiquote <qq template>) +syntax: `<qq template> +auxiliary syntax: unquote +auxiliary syntax: , +auxiliary syntax: unquote-splicing +auxiliary syntax: ,﹫ + +“Quasiquote”expressions are useful for constructing a list or vector structure when some +but not all of the desired structure is known in advance. If no commasappear within the +<qq template>, the result of evaluating `<qq template> is equivalent to the result of +evaluating '<qq template>. If a commaappears within the <qq template>, however, the +expression following the comma is evaluated (“unquoted”) and its result is inserted into +the structure instead of the comma and the expression. If a comma appears followed +without intervening whitespace by a commercial at-sign (﹫),then it is an error if the +following expression does not evaluate to a list; the opening and closing parentheses of +the list are then “stripped away” and the elements of the list are inserted in place of the +comma at-sign expression sequence. A comma at-sign normally appears only within a list +or vector <qq template>. + + Note: In order to unquote an identifier beginning with @, it is necessary to use either + an explicit unquote or to put whitespace after the comma, to avoid colliding with the + comma at-sign sequence. + +`(list ,(+ 1 2) 4) ⟹ (list 3 4) +(let ((name 'a)) `(list ,name ',name)) +⟹ (list a (quote a)) +`(a ,(+ 1 2) ,@(map abs '(4 -5 6)) b) +⟹ (a 3 4 5 6 b) +`(( foo ,(- 10 3)) ,@(cdr '(c)) . ,(car '(cons))) +⟹ ((foo 7) . cons) +`#(10 5 ,(sqrt 4) ,@(map sqrt '(16 9)) 8) +⟹ #(10 5 2 4 3 8) +(let ((foo '(foo bar)) (@baz 'baz)) + `(list ,@foo , @baz)) +⟹ (list foo bar baz) Quasiquote expressions can be nested. Substitutions are made only +for unquoted components appearing at the same nesting level as the outermost +quasiquote. The nesting level increases by one inside each successive quasiquotation, and +decreases by one inside each unquotation. + +`(a `(b ,(+ 1 2) ,(foo ,(+ 1 3) d) e) f) +⟹ (a `(b ,(+ 1 2) ,(foo 4 d) e) f) +(let ((name1 'x) + (name2 'y)) + `(a `(b ,,name1 ,',name2 d) e)) +⟹ (a `(b ,x ,'y d) e) A quasiquote expression may return either newly allocated, mutable +objects or literal structure for any structure that is constructed at run time during the +evaluation of the expression. Portions that do not need to be rebuilt are always literal. +Thus, + +(let ((a 3)) `((1 2) ,a ,4 ,'five 6)) may be treated as equivalent to either of the following +expressions: + +`((1 2) 3 4 five 6) + +(let ((a 3)) + (cons '(1 2) + (cons a (cons 4 (cons 'five '(6)))))) However, it is not equivalent to this expression: + +(let ((a 3)) (list (list 1 2) a 4 'five 6)) The two notations `<qq template> and (quasiquote <qq +template>) are identical in all respects. ,<expression> is identical to (unquote +<expression>), and ,@<expression> is identical to (unquote-splicing <expression>). The +write procedure may output either format. + +(quasiquote (list (unquote (+ 1 2)) 4)) +⟹ (list 3 4) +'(quasiquote (list (unquote (+ 1 2)) 4)) +⟹ `(list ,(+ 1 2) 4) + i.e., (quasiquote (list (unquote (+ 1 2)) 4)) + +It is an error if any of the identifiers quasiquote, unquote, or unquote-splicing appear in +positions within a <qq template> otherwise than as described above. + @node Case-lambda @subsection Case-lambda + +case-lambda library syntax: (case-lambda <clause> …) + +Syntax: Each <clause> is of the form (<formals> <body>), where <formals> and <body> +have the same syntax as in a lambda expression. + +Semantics: A case-lambda expression evaluates to a procedure that accepts a variable +number of arguments and is lexically scoped in the same manner as a procedure resulting +from a lambda expression. When the procedure is called, the first <clause> for which the +arguments agree with <formals> is selected, where agreement is specified as for the +<formals> of a lambda expression. The variables of <formals> are bound to fresh +locations, the values of the arguments are stored in those locations, the <body> is +evaluated in the extended environment, and the results of <body> are returned as the +results of the procedure call. + +It is an error for the arguments not to agree with the <formals> of any <clause>. + +(define range + (case-lambda + ((e) (range 0 e)) + ((b e) (do ((r '() (cons e r)) + (e (- e 1) (- e 1))) + ((< e b) r))))) + +(range 3) ⟹ (0 1 2) +(range 3 5) ⟹ (3 4) + @node Macros @section Macros + +Scheme programs can define and use new derived expression types, called +macros.Program-defined expression types have the syntax + +(<keyword> <datum> ...)where <keyword> is an identifier that uniquely determines the +expression type. This identifier is called the syntactic keyword, or simply keyword, of the +macro. The number of the <datum>s, and their syntax, depends on the expression type. + +Each instance of a macro is called a useof the macro. The set of rules that specifies how a +use of a macro is transcribed into a more primitive expression is called the transformerof +the macro. + +The macro definition facility consists of two parts: + +* A set of expressions used to establish that certain identifiers are macro keywords, + associate them with macro transformers, and control the scope within which a macro + is defined, and + +* a pattern language for specifying macro transformers. + +The syntactic keyword of a macro can shadow variable bindings, and local variable +bindings can shadow syntactic bindings. Two mechanisms are provided to prevent +unintended conflicts: + +* If a macro transformer inserts a binding for an identifier (variable or keyword), the + identifier will in effect be renamed throughout its scope to avoid conflicts with other + identifiers. Note that a global variable definition may or may not introduce a binding; + see section 5.3. + +* If a macro transformer inserts a free reference to an identifier, the reference refers to + the binding that was visible where the transformer was specified, regardless of any + local bindings that surround the use of the macro. + +In consequence, all macros defined using the pattern language are “hygienic” and +“referentially transparent” and thus preserve Scheme’s lexical scoping. [21, 22, 2, 9, 12] + +Implementations may provide macro facilities of other types. + @node Binding constructs for syntactic keywords @subsection Binding constructs for syntactic keywords + +The let-syntax and letrec-syntax binding constructs are analogous to let and letrec, but +they bind syntactic keywords to macro transformers instead of binding variables to +locations that contain values. Syntactic keywords can also be bound globally or locally +with define-syntax; see section 5.4. + +syntax: (let-syntax <bindings> <body>) + +Syntax: <Bindings> has the form + +((<keyword> <transformer spec>) …)Each <keyword> is an identifier, each <transformer +spec> is an instance of syntax-rules, and <body> is a sequence of zero or more +definitions followed by one or more expressions. It is an error for a <keyword> to +appear more than once in the list of keywords being bound. + +Semantics: The <body> is expanded in the syntactic environment obtained by extending +the syntactic environment of the let-syntax expression with macros whose keywords are +the <keyword>s, bound to the specified transformers. Each binding of a <keyword> has +<body> as its region. + +(let-syntax ((given-that (syntax-rules () + ((given-that test stmt1 stmt2 ...) + (if test + (begin stmt1 + stmt2 ...)))))) + (let ((if #t)) + (given-that if (set! if 'now)) + if)) ⟹ now + +(let ((x 'outer)) + (let-syntax ((m (syntax-rules () ((m) x)))) + (let ((x 'inner)) + (m)))) ⟹ outer + +syntax: (letrec-syntax <bindings> <body>) + +Syntax: Same as for let-syntax. + +Semantics: The <body> is expanded in the syntactic environment obtained by extending +the syntactic environment of the letrec-syntax expression with macros whose keywords +are the <keyword>s, bound to the specified transformers. Each binding of a <keyword> +has the <transformer spec>s as well as the <body> within its region, so the transformers +can transcribe expressions into uses of the macros introduced by the letrec-syntax +expression. + +(letrec-syntax + ((my-or (syntax-rules () + ((my-or) #f) + ((my-or e) e) + ((my-or e1 e2 ...) + (let ((temp e1)) + (if temp + temp + (my-or e2 ...))))))) + (let ((x #f) + (y 7) + (temp 8) + (let odd?) + (if even?)) + (my-or x + (let temp) + (if y) + y))) ⟹ 7 + @node Pattern language @subsection Pattern language + +A <transformer spec> has one of the following forms: + +syntax: (syntax-rules (<pattern literal> …) + <syntax rule> …) +syntax: (syntax-rules <ellipsis> (<pattern literal> …) + <syntax rule> …) +auxiliary syntax: _ +auxiliary syntax: … + +Syntax: It is an error if any of the <pattern literal>s, or the <ellipsis> in the second form, is +not an identifier. It is also an error if <syntax rule> is not of the form + +(<pattern> <template>)The <pattern> in a <syntax rule> is a list <pattern> whose first +element is an identifier. + +A <pattern> is either an identifier, a constant, or one of the following + +(<pattern> …) +(<pattern> <pattern> … . <pattern>) +(<pattern> … <pattern> <ellipsis> <pattern> …) +(<pattern> … <pattern> <ellipsis> <pattern> … + . <pattern>) +#(<pattern> …) +#(<pattern> … <pattern> <ellipsis> <pattern> …)and a <template> is either an identifier, a +constant, or one of the following (<element> …) +(<element> <element> … . <template>) +(<ellipsis> <template>) +#(<element> …)where an <element> is a <template> optionally followed by an <ellipsis>. +An <ellipsis> is the identifier specified in the second form of syntax-rules, or the default +identifier ... (three consecutive periods) otherwise. + +Semantics: An instance of syntax-rules produces a new macro transformer by specifying a +sequence of hygienic rewrite rules. A use of a macro whose keyword is associated with a +transformer specified by syntax-rules is matched against the patterns contained in the +<syntax rule>s, beginning with the leftmost <syntax rule>. When a match is found, the +macro use is transcribed hygienically according to the template. + +An identifier appearing within a <pattern> can be an underscore (_), a literal identifier +listed in the list of <pattern literal>s, or the <ellipsis>. All other identifiers appearing +within a <pattern> are pattern variables. + +The keyword at the beginning of the pattern in a <syntax rule> is not involved in the +matching and is considered neither a pattern variable nor a literal identifier. + +Pattern variables match arbitrary input elements and are used to refer to elements of +the input in the template. It is an error for the same pattern variable to appear more +than once in a <pattern>. + +Underscores also match arbitrary input elements but are not pattern variables and so +cannot be used to refer to those elements. If an underscore appears in the <pattern +literal>s list, then that takes precedence and underscores in the <pattern> match as +literals. Multiple underscores can appear in a <pattern>. + +Identifiers that appear in (<pattern literal> …) are interpreted as literal identifiers to be +matched against corresponding elements of the input. An element in the input matches +a literal identifier if and only if it is an identifier and either both its occurrence in the +macro expression and its occurrence in the macro definition have the same lexical +binding, or the two identifiers are the same and both have no lexical binding. + +A subpattern followed by <ellipsis> can match zero or more elements of the input, +unless <ellipsis> appears in the <pattern literal>s, in which case it is matched as a literal. + +More formally, an input expression E matches a pattern P if and only if: + +* P is an underscore (_). + +* P is a non-literal identifier; or + +* P is a literal identifier and E is an identifier with the same binding; or + +* P is a list (P1 … Pn) and E is a list of n elements that match P1 through Pn, respectively; + or + +* P is an improper list (P1P2 … Pn . Pn+1) and E is a list or improper list of n or more + elements that match P1 through Pn, respectively, and whose nth tail matches Pn+1; or + +* P is of the form (P1 … PkPe <ellipsis> Pm+1 … Pn) where E is a proper list of n elements, + the first k of which match P1 through Pk, respectively, whose next m−k elements each + match Pe, whose remaining n−m elements match Pm+1 through Pn; or + +* P is of the form (P1 … PkPe <ellipsis> Pm+1 … Pn . Px) where E is a list or improper list of n + elements, the first k of which match P1 through Pk, whose next m−k elements each + match Pe, whose remaining n−m elements match Pm+1 through Pn, and whose nth and + final cdr matches Px; or + +* P is a vector of the form #(P1 … Pn) and E is a vector of n elements that match P1 + through Pn; or + +* P is of the form #(P1 … PkPe <ellipsis> Pm+1 …Pn) where E is a vector of n elements the + first k of which match P1 through Pk, whose next m−k elements each match Pe, and + whose remaining n−m elements match Pm+1 through Pn; or + +* P is a constant and E is equal to P in the sense of the equal? procedure. + +It is an error to use a macro keyword, within the scope of its binding, in an expression +that does not match any of the patterns. + +When a macro use is transcribed according to the template of the matching <syntax +rule>, pattern variables that occur in the template are replaced by the elements they +match in the input. Pattern variables that occur in subpatterns followed by one or more +instances of the identifier <ellipsis> are allowed only in subtemplates that are followed +by as many instances of <ellipsis>. They are replaced in the output by all of the elements +they match in the input, distributed as indicated. It is an error if the output cannot be +built up as specified. + +Identifiers that appear in the template but are not pattern variables or the identifier +<ellipsis> are inserted into the output as literal identifiers. If a literal identifier is inserted +as a free identifier then it refers to the binding of that identifier within whose scope the +instance of syntax-rules appears. If a literal identifier is inserted as a bound identifier +then it is in effect renamed to prevent inadvertent captures of free identifiers. + +A template of the form (<ellipsis> <template>) is identical to <template>, except that +ellipses within the template have no special meaning. That is, any ellipses contained +within <template> are treated as ordinary identifiers. In particular, the template +(<ellipsis> <ellipsis>) produces a single <ellipsis>. This allows syntactic abstractions to +expand into code containing ellipses. + +(define-syntax be-like-begin + (syntax-rules () + ((be-like-begin name) + (define-syntax name + (syntax-rules () + ((name expr (... ...)) + (begin expr (... ...)))))))) + +(be-like-begin sequence) +(sequence 1 2 3 4) ⟹ 4 As an example, if let and cond are defined as in section 7.3 then +they are hygienic (as required) and the following is not an error. + +(let ((=> #f)) + (cond (#t => 'ok))) ⟹ ok The macro transformer for cond recognizes => as a local +variable, and hence an expression, and not as the base identifier =>, which the macro +transformer treats as a syntactic keyword. Thus the example expands into + +(let ((=> #f)) + (if #t (begin => 'ok))) instead of + +(let ((=> #f)) + (let ((temp #t)) + (if temp ('ok temp)))) which would result in an invalid procedure call. + @node Signaling errors in macro transformers @subsection Signaling errors in macro transformers +syntax: (syntax-error <message> <args> …) + +syntax-error behaves similarly to error (6.11) except that implementations with an +expansion pass separate from evaluation should signal an error as soon as syntax-error +is expanded. This can be used as a syntax-rules <template> for a <pattern> that is an +invalid use of the macro, which can provide more descriptive error messages. +<message> is a string literal, and <args> arbitrary expressions providing additional +information. Applications cannot count on being able to catch syntax errors with +exception handlers or guards. + +(define-syntax simple-let + (syntax-rules () + ((_ (head ... ((x . y) val) . tail) + body1 body2 ...) + (syntax-error + "expected an identifier but got" + (x . y))) + ((_ ((name val) ...) body1 body2 ...) + ((lambda (name ...) body1 body2 ...) + val ...)))) + @node Program structure @chapter Program structure + @node Programs @section Programs + +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. + @node Import declarations @section Import declarations + +An import declaration takes the following form: + +(import <import-set> …) +An import declaration provides a way to import identifiers exported by a library. Each +<import set> names a set of bindings from a library and possibly specifies local names for +the imported bindings. It takes one of the following forms: + +* <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. + @node Variable definitions @section Variable definitions @node Top level definitions