[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Message a011267 LONG message - part 1
Received: from csnet-relay.arpa by CSNET-SH.ARPA id a028166; 18 Mar 85 13:26 EST
Date: Mon, 18 Mar 85 10:55:42 EST
From: CSNET-RELAY Memo Service (MMDF) <mmdf@CSNET-RELAY.ARPA>
Subject: Failed mail (msg.a011267)
Sender: mmdf@CSNET-RELAY.ARPA
To: Postmaster@CSNET-RELAY.ARPA
Your message could not be delivered to
'scheme@mit-mc.ARPA (host: mit-mc.arpa) (queue: smtp)' for the following
reason: ' Message is too large to mail; use FTP.'
Your message follows:
Received: from indiana by csnet-relay.csnet id a011267; 18 Mar 85 9:36 EST
Date: Mon, 18 Mar 85 01:24:29 est
From: willc@Indiana (Will Clinger)
Received: by iuvax.UUCP; id AA06606; Mon, 18 Mar 85 01:24:29 est
To: scheme@mit-mc
Subject: DRAFT of Revised Revised Report (LONG message)
Here is the DRAFT of the final report on the Brandeis workshop.
It is missing all its appendices, and a couple of sections that
deal with the lexical syntax of numbers need more work. Please
read it and tell me what you think. We'd like to have your
comments by 1 April so we can send it to press.
The font information has been stripped for posting to
scheme@mit-mc. Some ambiguities probably result, but please don't
get upset about them.
If you have anything more to say about Chris Hanson's work on
strings, please say it soon. We'd like to include Chris's work
in this report.
-- Will Clinger
willc@indiana
Table of Contents
Part I: Introduction to Scheme
I.0 Brief history of Scheme
I.1 Syntax of Scheme
I.2 Semantics of Scheme
Part II: A catalog of Scheme
II.0 Notational conventions
II.1 Special forms
II.2 Booleans
II.3 Equivalence predicates
II.4 Pairs and lists
II.5 Symbols
II.6 Numbers (part 1)
II.7 Numbers (part 2)
II.8 Strings
II.9 Vectors
II.10 The object table
II.11 Procedures
II.12 Ports
II.13 Input
II.14 Output
References
Index (not yet ready)
Acknowledgements
This report is primarily the work of a group of people who met
at Brandeis University for two days in October 1984. The
participants at that workshop were Hal Abelson (MIT), Norman
Adams (Yale), David Bartley (Texas Instruments), Gary Brooks,
(Texas Instruments, Indiana University), William Clinger
(Indiana University), Dan Friedman (Indiana University), Robert
Halstead (MIT), Chris Hanson (MIT), Chris Haynes (Indiana
University), Eugene Kohlbecker (Indiana University), Don Oxley
(Texas Instruments), Jonathan Rees (MIT), Bill Rozas (MIT),
Gerald Sussman (MIT), and Mitchell Wand (Indiana University,
Brandeis). Kent Pitman (MIT) made valuable contributions to the
agenda for the workshop but was unable to attend the sessions.
We would like also to thank the following people for their
comments and criticisms in the months following the workshop:
Kent Dybvig, Andy Freeman, Yekta Gursel, Paul Hudak, Chris
Lindblad, Guy Steele Jr.
We thank Dan Friedman and Chris Haynes for permission to use
text from the Scheme 311 Version 4 reference manual. We
acknowledge the influence of manuals for MIT Scheme, T, Scheme
84, and Common Lisp.
Part I: Introduction to Scheme
I.0 Brief history of Scheme
Scheme is a programming language invented by Guy Lewis Steele Jr
and Gerald Jay Sussman. It is a statically scoped dialect of
Lisp with an exceptionally clear and simple semantics.
The first description of Scheme was written in 1975 [\ref]. A
Revised Report [\ref] appeared in 1978, which described the
evolution of the language as its MIT implementation was upgraded
to support an innovative compiler [\ref]. Three distinct
projects began in 1981 and 1982 to use variants of Scheme for
courses at MIT, Yale, and Indiana University [\ref, ref, ref].
An excellent introductory computer science textbook using Scheme
was published in 1984 [\ref].
As might be expected of a language used primarily for education
and research, Scheme has always evolved rapidly. This was no
problem when Scheme was used only within MIT, but as Scheme
became more widespread local subdialects 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. This paper reports their unanimous recommendations
augmented by committee work in the areas of input/output and
arithmetic.
Scheme shares with Common Lisp [\ref] the goal of a core
language common to several implementations. Scheme differs from
Common Lisp in that the purpose of the common language has as
much to do with porting ideas as with porting code. It is
appropriate therefore that Scheme is much smaller, is less
pervasively specified, and will evolve faster than Common Lisp.
I.1 Syntax
Formal definitions of the lexical and context-free syntaxes of
Scheme will be added as appendices.
Identifiers
Most identifiers allowed by other programming languages are also
acceptable to Scheme. The precise rules for forming identifiers
vary among implementations of Scheme, but in all implementations
a sequence of characters that contains no special characters and
begins with a character that cannot begin a number is an
identifier. There may be other identifiers as well, and in
particular the following are identifiers:
+ - 1+ -1+
It is guaranteed that the following characters cannot begin a
number, so identifiers other than the four listed above should
begin with one of:
a b c d e f g h i j k l m n o p q r s t u v w x y z
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
! $ % & * / : < = > ? ~
Subsequent characters of the identifier should be drawn from:
a b c d e f g h i j k l m n o p q r s t u v w x y z
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
0 1 2 3 4 5 6 7 8 9
! $ % & * / : < = > ? ^ _ . ~
The case in which the letters of an identifier are typed is
immaterial. For example, Foo is the same identifier as FOO.
The following characters are special, and should never be used
in an identifier:
) ( ] [ } { " ; blank
Scheme deliberately does not specify whether the following
characters can be used in identifiers:
# ' ` , @ \ |
Rationale: Some implementations might want to use backwhack ( \)
and vertical bar ( | ) as in Common Lisp. As for the others
there are two schools of thought. One school argues that
disallowing special characters in identifiers allows the
computer to catch more typing errors. The other school agrees
only for special characters that come in pairs, because errors
that involve only the unpaired special characters are easy to
see.
Numbers
For a description of the notations used for numbers, see section
II.7. A concise summary of the notations used to write numbers
will be added to this section, and a formal description will be
part of the appendix on lexical syntax.
Comments
A semicolon indicates the start of a comment. The comment
continues to the end of the line on which the semicolon appears.
Comments are invisible to Scheme, but the end of the line is
visible as whitespace. This prevents a comment from appearing
in the middle of an identifier or number. Comments may appear
inside a string that extends over more than one line, but it is
probably a bad idea to write such strings because their contents
are implementation-dependent.
Other notations
Left and right parentheses are used for grouping and to notate
lists as described in section II.4. Left and right square
brackets and curly braces are not used in Scheme right now but
are reserved for unspecified future uses.
The quote (') and backquote (`) characters are used to indicate
constant or almost-constant data as described in section II.1.
The comma is used together with the backquote, and the atsign
(@) is used together with the comma.
The doublequote character is used to notate strings as described
in section II.8.
The sharp sign (octathorp) is used for a variety of purposes
depending on the character that follows it. A sharp sign
followed by a left parenthesis signals the beginning of a
vector, as described in section II.9. A sharp sign followed by
an exclamation point is used to notate one of the special values
#!true, #!false, and #!null. A sharp sign followed by a
backslash is used to notate characters as described in section
II.8. A sharp sign followed by any of a number of letters is
used to notate numbers as described in section II.7.
Context free grammar for Scheme
The following grammar is ambiguous because a <special form>
looks like a <procedure call>. Some implementations resolve the
ambiguity by reserving the identifiers that serve as keywords of
special forms, while other implementations allow the keyword
meaning of an identifier to be shadowed by lexical bindings.
<expression> ::= <constant>
| <identifier>
| <special form>
| <procedure call>
<constant> ::= <numeral> | #!true | #!false | #!null
| (quote <datum>) | '<datum>
<special form> ::= (<keyword> ...)
<procedure call> ::= (<expression> <arguments>)
<arguments> ::= <empty> | <expression> <arguments>
<datum> stands for any written representation of a Scheme
object, as described in the sections that follow. <identifier>
and <numeral> have already been described informally. <special
form> stands for one of the special forms whose syntax is
described in section II.1. For uniformity the other kinds of
expressions are also described in that section as though they
were special forms.
I.2 Semantics
The formal semantics of Scheme will be the subject of an
appendix to be added. The detailed informal semantics of Scheme
is the subject of Part II. This section gives a quick review of
Scheme's major characteristics.
Scheme is a statically scoped programming language, meaning that
each use of an identifier is associated with a lexically
apparent binding of that identifier. In this respect Scheme is
like Algol 60, Pascal, and C but unlike dynamically scoped
languages such as APL and traditional Lisp.
Scheme has latent as opposed to manifest types, which means that
types are associated with values (also called objects) rather
than with variables. (Some authors refer to languages with
latent types as weakly typed or dynamically typed languages.)
Other languages with latent types are APL, Snobol, and other
dialects of Lisp. Languages with manifest types (sometimes
referred to as strongly typed or statically typed languages)
include Algol 60, Pascal, and C.
All objects created in the course of a Scheme computation,
including all procedures and variables, have unlimited extent.
This means in effect that 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 mathematically that the
object cannot possibly matter to any future computation. Scheme
is a practical programming language only because there exist
fairly efficient "garbage collection" algorithms for performing
these proofs. Other languages in which most objects have
unlimited extent include APL and Common Lisp.
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. Other languages with these
properties include Common Lisp, ML, and KRC.
Arguments to Scheme procedures are always passed by value, which
means that the actual argument expressions are evaluated before
the procedure actually gains control, whether the procedure
needs the result of the evaluation or not. ML, C, and APL are
three good examples of other languages that always pass
arguments by value. KRC is a good example of a language that
passes arguments by name, so that an argument expression is
evaluated only if its value is needed by the procedure.
Part II: A catalog of Scheme
II.0 Notational conventions
This part of the report is a catalog of the special forms and
procedures that make up Scheme. The special forms are described
in section II.1, and the procedures are described in the
following sections. Each section is organized into entries,
with one entry (usually) for each special form or procedure.
Each entry begins with a header line that includes the name of
the special form or procedure in bold face type within a
template for the special form or a call to the procedure. The
names of the arguments to a procedure are italicized, as are the
syntactic components of a special form. A notation such as
expr ...
indicates zero or more occurrences of expr, and so
expr1 expr2 ...
indicates at least one expr.
At the right of the header line one of the following categories
will appear:
special form
constant
variable
procedure
essential special form
essential constant
essential variable
essential procedure
A special form is a syntactic class of expressions, usually
identified by a keyword. A constant is something that is
lexically recognizable as a constant. A variable is an
identifier that is bound to a location in which values (also
called objects) can be stored. Those variables that initially
hold procedure values are identified as procedures.
Implementations are free to omit features of Scheme or to add
extensions, provided the extensions are not in conflict with the
language reported here. It is guaranteed, however, that every
implementation of Scheme will support the essential special
forms, constants, variables, and procedures.
Any Scheme value can be used as a boolean expression for the
purposes of a conditional test. As explained in section II.2,
most values count as true, but a few -- notably #!false -- count
as false. This manual uses the word "true" to refer to any
Scheme value that counts as true in a conditional expression,
and the word "false" to refer to any Scheme value that counts as
false.
II.1. Special forms
Identifiers have two uses within Scheme programs. When an
identifier appears within a quoted constant (see quote), it is
being used as data as described in the section on symbols.
Otherwise it is being used as a name. There are two kinds of
things that an identifier can name in Scheme: special forms and
variables. A special form is a syntactic class of expressions,
and an identifier that names a special form is called the
keyword of that special form. A variable, on the other hand, is
a location where a value can be stored. An identifier that
names a variable is said to be bound to that location. The set
of all such bindings in effect at some point in a program is
known as the environment in effect at that point.
Certain special forms are used to allocate storage for new
variables and to bind identifiers to those new variables. The
most fundamental of these binding constructs is the lambda
special form, because all other binding constructs can be
explained in terms of lambda expressions. The other binding
constructs are the let, let*, letrec, internal definition (see
define), rec, define!, defrec!, and do special forms.
Like Algol or Pascal, and unlike most other dialects of Lisp
except for Common Lisp, Scheme is a statically scoped language
with block structure. To each place where an identifier is
bound in a program there corresponds a region of the program
within which the binding is effective. The region varies
according to the binding construct that establishes the binding;
if the binding is established by a lambda expression, for
example, then the region is the entire lambda expression. Every
use of an identifier in a variable reference or assignment
refers to the binding of the identifier that set up 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 identifier that was in
effect when Scheme started up, if any; if there is no binding
for the identifier, it is said to be unbound.
variable essential special form
An expression consisting of an identifier that is not the
keyword of a special form is a variable reference. The value
obtained for the variable reference is the value stored in the
location to which variable is bound. An error is signalled if
variable is unbound.
(procedure arg1 ...) essential special form
A list of expressions whose first element is not the keyword of
a special form indicates a procedure call. The procedure and
argument expressions are evaluated and the procedure is passed
the values of the argument expressions. In constrast to other
dialects of Lisp the order of evaluation is not specified, and
the procedure expression and the argument expressions are always
evaluated in exactly the same way.
(+ 3 4) --> 7
((if #!false + *) 3 4) --> 12
(quote constant) essential special form
'constant essential special form
Evaluates to constant. 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 constant) may be abbreviated as 'constant. 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)
Numbers, strings, and the constants #!true, #!false, and #!null
need not be quoted.
'"abc" --> "abc"
"abc" --> "abc"
'145932 --> 145932
145932 --> 145932
'#!true --> #!true
#!true --> #!true
(lambda (var1 ...) expr) essential special form
Each var must be an identifier. The lambda expression evaluates
to a procedure with formal argument list (var1 ...) and
procedure body expr. 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 identifiers in the formal
argument list to fresh locations, the corresponding actual
argument values will be stored in those locations, and expr will
then be evaluated in the extended environment. The result of
expr will be returned as the result of the procedure call.
(lambda (x) (+ x x)) --> #<PROCEDURE>
((lambda (x) (+ x x)) 4) --> 8
(define reverse-subtract
(lambda (x y) (- y x))) --> reverse-subtract
(reverse-subtract 7 10) --> 3
(define foo
(let ((x 4))
(lambda (y) (+ x y)))) --> foo
(foo 6) --> 10
(lambda (var1 ...) expr1 expr2 ...) essential special form
Equivalent to (lambda (var1 ...) (begin expr1 expr2 ...)).
(lambda var expr1 expr2 ...) essential special form
Returns a procedure that when later called with some arguments
will bind var to a fresh location, convert the sequence of
actual arguments into a list, and store that list in the binding
of var.
((lambda x x) 3 4 5 6) --> (3 4 5 6)
One last variation on the formal argument list provides for a
so-called rest argument. If a space/dot/space sequence precedes
the last argument in the formal argument list, then the value
stored in the binding of the last formal argument will be a list
of the actual arguments left over after all the other actual
arguments have been matched up against the formal arguments.
((lambda (x y . z) z) 3 4 5 6) --> (5 6)
(if condition consequent alternative) essential special form
(if condition consequent) essential special form
First evaluates condition. If it yields a true value (see
section II.2), then consequent is evaluated and its value is
returned. Otherwise alternative is evaluated and its value is
returned. If no alternative is specified, then the if
expression is evaluated only for its effect, and 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
(cond clause1 clause2 ...) essential special form
Each clause must be a list of one or more expressions. The
first expression in each clause is a boolean expression that
serves as the guard for the clause. The guards are evaluated in
order until one of them evaluates to a true value (see section
II.2). When a guard evaluates true, then the remaining
expressions in its clause are evaluated in order, and the result
of the last expression in the selected clause is returned as the
result of the entire expression. If the selected clause
contains only the guard, then the value of the guard is returned
as the result. If all tests evaluate to false values, then the
result of the conditional expression is unspecified.
(cond ((>? 3 2) 'greater)
((<? 3 2) 'less)) --> greater
The special keyword else may be used as a guard to obtain the
effect of an otherwise clause.
(cond ((>? 3 3) 'greater)
((<? 3 3) 'less)
(else 'equal)) --> equal
The above forms for the clauses are essential. Some
implementations support yet another form of clause such that
(cond (form1 => form2) ...)
is equivalent to
(let ((form1_result form1)
(thunk2 (lambda () form2))
(thunk3 (lambda () (cond ...))))
(if form1_result
((thunk2) form1_result)
(thunk3)))
(case expr clause1 clause2 ...) special form
Each clause is a list whose first element is a selector followed
by one or more expressions. Each selector should be a list of
values. The selectors are not evaluated. Instead expr is
evaluated and its result is compared against successive
selectors using the memv procedure until a match is found. Then
the expressions in the selected clause are evaluated from left
to right and the result of the last expression in the clause is
returned as the result of the case expression. If no selector
matches then the result of the case expression is unspecified.
(case (* 2 3)
((2 3 5 7) 'prime)
((1 4 6 8 9) 'composite)) --> composite
(case (car '(c d))
((a) 'a)
((b) 'b)) --> unspecified
The special keyword else may be used as a selector to obtain the
effect of an otherwise clause.
(case (car '(c d))
((a e i o u) 'vowel)
((y) 'y)
(else 'consonant)) --> consonant
(and expr1 ...) special form
Evaluates the exprs from left to right, returning false as soon
as one evaluates to a false value (see section II.2). Any
remaining expressions are not evaluated. If all the expressions
evaluate to true values, the value of the last expression is
returned.
(and (=? 2 2) (>? 2 1)) --> #!true
(and (=? 2 2) (<? 2 1)) --> #!false
(and 1 2 'c '(f g)) --> (f g)
(or expr1 ...) special form
Evaluates the exprs from left to right, returning the value of
the first expr that evaluates to a true value (see section
II.2). Any remaining expressions are not evaluated. If all
expressions evaluate to false values, false is returned.
(or (=? 2 2) (>? 2 1)) --> #!true
(or (=? 2 2) (<? 2 1)) --> #!true
(or #!false #!false #!false) --> #!false
(or (memq 'b '(a b c)) (/ 3 0)) --> (b c)
(let ((var1 form1) ...) expr1 expr2 ...) essential special form
Evaluates the forms in the current environment (in some
unspecified order), binds the vars to fresh locations holding
the results, and then evaluates the exprs in the extended
environment, returning the value of the last one. Each binding
of a var has expr1 expr2 ... as its region.
(let ((x 2)
(y 3))
(* x y)) --> 6
(let ((x 2)
(y 3))
(let ((foo (lambda (z)
(+ x y z)))
(x 7))
(foo 4))) --> 9
let and letrec give Scheme a block structure. The difference
between let and letrec is that in a let the forms are not within
the regions of the vars being bound. See letrec.
Some implementations of Scheme permit a "named let" syntax in
which
(let name ((var1 form1) ...) expr1 expr2 ...)
is equivalent to
((rec name (lambda (id1 ...) expr1 expr2 ...))
form1 ...)
(let* ((var1 form1) ...) expr1 expr2 ...) special form
Similar to let, but the bindings are performed sequentially from
left to right and the region of a binding indicated by (var
form) 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.
(letrec ((var1 form1) ...) expr1 expr2 ...)essential special form
Binds the vars to fresh locations holding undefined values,
evaluates the forms in the resulting environment (in some
unspecified order), assigns to each var the result of the
corresponding form, evaluates the exprs sequentially in the
resulting environment, and returns the value of the last expr.
Each binding of a var has the entire letrec expression as its
region, making it possible to define mutually recursive
procedures. See let.
(letrec ((x 2)
(y 3))
(letrec ((foo (lambda (z)
(+ x y z)))
(x 7))
(foo 4))) --> 14
(letrec ((even? (lambda (n)
(if (zero? n)
#!true
(odd? (-1+ n)))))
(odd? (lambda (n)
(if (zero? n)
#!false
(even? (-1+ n))))))
(even? 88))
--> #!true
One restriction on letrec is very important: it must be possible
to evaluate each form without referring to the value of a var.
If this restriction is violated, then the effect is undefined,
and an error may be signalled during evaluation of the forms.
The restriction is necessary because Scheme uses call by value
rather than call by name. In the most common uses of letrec,
all the forms are lambda expressions and the restriction is
satisfied automatically.
(rec var expr) special form
Equivalent to (letrec ((var expr)) var). rec is useful for
defining self-recursive procedures.
(named-lambda (name var1 ...) expr ...) special form
Equivalent to
(rec name (lambda (var1 ...) expr ...))
Rationale: Some implementatations may find it easier to provide
good debugging information when named-lambda is used instead of
rec.
(define var expr) essential special form
When typed at top level (so that it is not nested within any
other expression), this form has essentially the same effect as
(set! var expr) if var is bound. If var is not bound, however,
then the define form will bind var before performing the
assignment, whereas it would be an error to perform a set! on an
unbound identifier. The value returned by a define form is not
specified.
(define add3 (lambda (x) (+ x 3))) --> unspecified
(add3 3) --> 6
(define first car) --> unspecified
(first '(1 2)) --> 1
The semantics just described is essential. Some implementations
also allow define expressions to appear at the beginning of the
body of a lambda, named-lambda, let, let*, or letrec expression.
Such expressions are known as internal definitions as opposed to
the top level definitions described above. The variable defined
by an internal definition is local to the body of the lambda,
named-lambda, let, let*, or letrec expression. That is, var is
bound rather than assigned, and the region set up by the binding
is the entire body of the lambda, named-lambda, let, let*, or
letrec expression. For example,
(let ((x 5))
(define foo
(lambda (y)
(bar x y)))
(define bar
(lambda (a b)
(+ (* a b) a)))
(foo (+ x 3))) --> 45
Internal definitions can always be converted into an equivalent
letrec expression. For example, the let expression in the above
example is equivalent to
(let ((x 5))
(letrec ((foo (lambda (y)
(bar x y)))
(bar (lambda (a b)
(+ (* a b) a))))
(foo (+ x 3))))
(define (var0 var1 ...) expr1 expr2 ...) special form
(define (form var1 ...) expr1 expr2 ...) special form
The first form, where var0 is an identifier, is equivalent to
(define var0 (rec var0 (lambda (var1 ...) expr1 expr2 ...))).
The second form, where form is a list, is sometimes convenient
for defining a procedure that returns another procedure as its
result. It is equivalent to
(define form (lambda (var1 ...) expr1 expr2 ...)).
(define! var expr) special form
If var is bound, then the define! form is equivalent to the
corresponding set!. If var is unbound, however, define! binds
var in the global environment before performing the assignment.
Rationale: This makes sense only for implementations with a
distinguished global environment.
(defrec! var expr) special form
Equivalent to (define! var (rec var expr)).
(set! var expr) essential special form
Stores the value of expr in the location to which var is bound.
expr is evaluated but var is not. The result of the set!
expression is unspecified.
(set! x 4) --> unspecified
(1+ x) --> 5
Rationale: set! expressions are Scheme's assignment statements.
Assignment statements are seldom used in good Scheme code.
Their major uses are to initialize variables accessed
interactively and to construct objects with local state.
(begin expr1 expr2 ...) essential special form
Evaluates the exprs sequentially from left to right and returns
the value of the last expr. Used to sequence side effects such
as input and output.
(begin (set! x 5)
(1+ x)) --> 6
Also
(begin (display "4 plus 1 equals ")
(display (1+ 4)))
prints
4 plus 1 equals 5
A number of special forms such as lambda and letrec implicitly
treat their bodies as begin expressions.
(sequence expr1 expr2 ...) special form
sequence is synonymous with begin.
Rationale: sequence was used in the Abelson and Sussman text,
but it should not be used in new code.
(do ((var1 init1 step1) ...) special form
(test expr1 ...)
stmt1 ...)
The do special form is an extremely general albeit complex
iteration macro. Each var must be an identifier and each init
and step must be expressions. The init expressions are
evaluated (in some unspecified order), the vars are bound to
fresh locations, the results of the init expressions are stored
in the bindings of the vars, and then the iteration phase
begins.
Each iteration begins by evaluating test; if the result is false
(see section II.2), then the stmts are evaluated in order for
effect, the steps are evaluated (in some unspecified order), the
results of the step expressions are stored in the bindings of
the vars, and the next iteration begins.
If test evaluates true, then the exprs are evaluated from left
to right and the value of the last expr is returned as the value
of the do expression. If no exprs are present, then the value
of the do expression is unspecified.
The region set up by the binding of a var consists of the entire
do expression except for the inits.
A step may be omitted, in which case the corresponding var is
not updated. When the step is omitted the init may be omitted
as well, in which case the initial value is not specified.
(do ((vec (make-vector 5))
(i 0 (1+ i)))
((=? 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
The do special form is essentially the same as the do macro in
Common Lisp. The main difference is that in Scheme the
identifier return is not bound; programmers that want to bind
return as in Common Lisp must do so explicitly (see
call-with-current-continuation).
`pattern macro special form
The backquote special form is useful for constructing a list
structure when most but not all of the desired structure is
known in advance. If no commas appear within the pattern, the
result of evaluating `pattern is equivalent (in the sense of
equal?) to the result of evaluating 'pattern. If a comma
appears within the pattern, however, the expression following
the comma is evaluated and its result is inserted into the
structure instead of the comma and the expression. If a comma
appears followed immediately by an at-sign (@), then the
following expression must 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 ,(+ 1 2) ,@(mapcar 1+ '(4 5 6)) b) --> (a 3 5 6 7 b)
`(((foo ,(- 10 3)) ,@(cdr '(c)) cons)) --> (((foo 7) cons))
Scheme does not have any standard facility for defining new
special forms.
Rationale: The ability to define new special forms creates
numerous problems. All current implementations of Scheme have
macro facilities that solve those problems to one degree or
another, but the solutions are quite different and it isn't
clear at this time which solution is best, or indeed whether any
of the solutions are truly adequate. Rather than standardize,
we are encouraging implementations to continue to experiment
with different solutions.
The main problems with traditional macros are: They must be
defined to the system before any code using them is loaded; this
is a common source of obscure bugs. They are usually global;
macros can be made to follow lexical scope rules as in Common
Lisp's macrolet, but many people find the resulting scope rules
confusing. Unless they are written very carefully, macros are
vulnerable to inadvertant capture of free variables; to get
around this, for example, macros may have to generate code in
which procedure values appear as quoted constants. There is a
similar problem with keywords if the keywords of special forms
are not reserved. If keywords are reserved, then either macros
introduce new reserved words, invalidating old code, or else
special forms defined by the programmer do not have the same
status as special forms defined by the system.
II.2. Booleans
The standard boolean objects for truth and falsity are written
as #!true and #!false. What really matters, though, are the
objects that the Scheme conditional expressions (if, cond, and,
or, do) will treat as though they were true or false. The
phrase "a true value" (or sometimes just "true") means any
object treated as true by the conditional expressions, and the
phrase "a false value" (or "false") means any object treated as
false by the conditional expressions.
Of all the standard Scheme values, only #!false and the empty
list count as false in conditional expressions. #!true, pairs
(and therefore lists), symbols, numbers, strings, vectors, and
procedures all count as true.
The empty list counts as false for historical reasons only, and
programs should not rely on this because future versions of
Scheme will probably do away with this nonsense.
Programmers accustomed to other dialects of Lisp should beware
that Scheme has already done away with the nonsense that
identifies the empty list with the symbol nil.
#!false essential constant
#!false is the boolean value for falsity. The #!false object is
self-evaluating. That is, it does not need to be quoted in
programs.
'#!false --> #!false
#!false --> #!false
#!true essential constant
#!true is the boolean value for truth. The #!true object is
self-evaluating, and does not need to be quoted in programs.
(not obj) essential procedure
Returns #!true if obj is false and returns #!false otherwise.
nil variable
t variable
As a crutch for programmers accustomed to other dialects of
Lisp, some implementations provide variables nil and t whose
initial values are #!false and #!true respectively. These
variables should not be used in new code.
II.3. Equivalence predicates
A predicate is a procedure that always returns #!true or
#!false. Of the equivalence predicates described in this
section, eq? is the most discriminating while equal? is the most
liberal. eqv? is very slightly less discriminating than eq?.
(eq? obj1 obj2) essential procedure
Returns #!true if obj1 is identical in all respects to obj2,
otherwise returns #!false. If there is any way at all that a