doc edits

svn: r6708
This commit is contained in:
Matthew Flatt 2007-06-20 08:54:40 +00:00
parent 8a7caa749e
commit ceb1b78cea
9 changed files with 710 additions and 437 deletions

View File

@ -62,6 +62,7 @@
(printf "\\definecolor{LightGray}{rgb}{0.90,0.90,0.90}\n")
(printf "\\newcommand{\\schemeinput}[1]{\\colorbox{LightGray}{\\hspace{-0.5ex}\\schemeinputcol{#1}\\hspace{-0.5ex}}}\n")
(printf "\\newcommand{\\highlighted}[1]{\\colorbox{PaleBlue}{\\hspace{-0.5ex}\\schemeinputcol{#1}\\hspace{-0.5ex}}}\n")
(printf "\\newcommand{\\techlink}[1]{#1}\n")
(printf "\\begin{document}\n")
(when (part-title-content d)
(printf "\\title{")

View File

@ -151,6 +151,28 @@
;; ----------------------------------------
(provide deftech tech)
(define (*tech make-elem style s)
(let* ([c (decode-content s)]
[s (regexp-replace* #px"[-\\s]+"
(regexp-replace
#rx"s$"
(string-foldcase (content->string c))
"")
" ")])
(make-elem style
c
(format "tech-term:~a" s))))
(define/kw (deftech #:body s)
(*tech make-target-element #f (list (apply defterm s))))
(define/kw (tech #:body s)
(*tech make-link-element "techlink" s))
;; ----------------------------------------
(provide defproc defproc* defstruct defthing defform defform* defform/subs defform*/subs defform/none
specform specform/subs
specsubform specspecsubform specsubform/inline

View File

@ -246,6 +246,15 @@
color: red;
}
.techlink {
text-decoration: none;
color: black;
}
.techlink:hover {
text-decoration: underline;
color: blue;
}
.schemeresult {
color: #0000af;
font-family: Courier; font-size: 80%;

View File

@ -1,202 +1,4 @@
#reader(lib "docreader.ss" "scribble")
@require["mz.ss"]
@title[#:tag "mz:expansion"]{Syntax Expansion}
Expansion recursively processes a syntax object to parse it. In
general, the parsing of a datum depends on its outermost shape:
@itemize{
@item{If it is a syntax-object symbol, also known as an
@defterm{identifier}, then a binding is determined using symbol
along with the lexical information in the identifier. The
binding determines the next parsing step.}
@item{If it is a syntax-object pair whose first element is an
identifier, then the identifier's binding is used (as in the
preceding case).}
@item{If it is a syntax-object pair, then a new syntax-object symbol
@scheme['#%app] is created using the lexical context of the
pair. If the resulting @scheme[#%app] identifier has no
binding, parsing fails with an @scheme[exn:fail:syntax]
exception. Otherwise, the new identifier is combined with the
original pair to form a new syntax-object pair (using the same
context as the original pair), and parsing starts again (i.e.,
it continues with the preceding case).}
@item{If it is any other syntax object, then a new syntax-object
symbol @scheme['#%datum] is created using the lexical context
of the original syntax object. If the resulting
@scheme[#%datum] identifier has no binding, parsing fails with
an @scheme[exn:fail:syntax] exception. Otherwise, the new
identifier is combined with the original syntax object in a new
syntax-object pair (using the same context as the original
pair), and parsing starts again (i.e., it continues with the
second case above).}
}
For either of the first two steps, if the identifier has no binding,
then a new syntax-object symbol @scheme['#%top] is created using the
lexical context of the identifier; if this @scheme[#%top] identifier
has no binding, then parsing fails with an @scheme[exn:fail:syntax]
exception. Otherwise, the new identifier is combined with the
original identifier in a new syntax-object pair (using the same
context as the original identifier), and parsing starts again.
Thus, the possibilities that do not fail lead to an identifier with a
particular binding. This binding refers to one of three things:
@itemize{
@item{A transformer binding, such as introduced by
@scheme[define-syntax] or @scheme[let-syntax]. If the
associated value is to a procedure of one argument, the
procedure is called as a syntax transformer (see
@secref["transformers"]), and parsing starts again with the
syntax-object result. If the transformer binding is to any
other kind of value, parsing fails with an
@scheme[exn:fail:syntax] exception.}
@item{A variable binding, such as introduced by a module-level
@scheme[define] or by @scheme[let]. In this case, if the form
being parsed is just an identifier, then it is parsed as a
run-time reference to the location of the corersponding
variable. If the form being parsed is a syntax-object list,
then an @scheme[#%app] is added to the front of the
syntax-object list in the same way as when the first item in
the syntax-object list is not an identifier (third case in the
previous enumeration), and parsing continues.}
@item{Core syntax, which is parsed as described in
@secref["mz:syntax"]. Parsing core syntactic forms typically
involves recursive parsing of sub-forms, and may introduce
bindings that control the parsing of sub-forms.}
}
Each expansion step occurs in a particular context, and transformers
and core-syntax parsing can depend on the context. For example, a
@scheme[module] form is allowed only in a top-level context. The
possible contexts are as follows:
@itemize{
@item{@defterm{top level} : outside of any module, definition, or
expression, except that sub-expressions of a top-level
@scheme[begin] form are also expanded as top-level forms.}
@item{@defterm{module begin} : inside the body of a module, as the
only form within the module.}
@item{@defterm{module body} : in the body of a module (inside the
moudule-begin layer).}
@item{@defterm{internal definition} : in a nested context that allows
both definitions and expressions.}
@item{@defterm{expression} : in a context where only expressions are
allowed.}
}
Different core syntax forms parse sub-forms in different contexts. For
example, a @scheme[let] form always parses the right-hand expressions
of a binding in an expression context, but it starts parsing the body
in an internal-definition context.
@section[#:tag "mz:intdef-body"]{Internal Definitions}
An internal-definition context corresponds to a partial expansion
step. A form that supports internal definitions starts by expanding
its first form in an internal-definition context, but only
partially. That is, it recursively expands only until the form becomes
one of the following:
@itemize{
@item{A @scheme[define-values] or @scheme[define-syntaxes] form: The
definition form is not expanded further. Instead, the next form
is expanded partially, and so on. As soon as an expression form
is found, the accumulated definition forms are converted to a
@scheme[letrec-values] (if no @scheme[define-syntaxes] forms
were found) or @scheme[letrec-syntaxes+values] form, moving the
expression forms to the body to be expanded in expression
context.
When a @scheme[define-values] form is discovered, the lexical
context of all syntax objects for the body sequence is
immediately enriched with bindings for the
@scheme[define-values] form before expansion continues. When a
@scheme[define-syntaxes] form is discovered, the right-hand
side is executed and a transformer binding is installed before
expansion continues.}
@item{A primitive expression form other than @scheme[begin]: The
expression will be further expanded in an expression context,
along with all remaining body forms. If any definitions were
found, this expansion takes place after conversion to a
@scheme[letrec-values] or @scheme[letrec-syntaxes+values]
form. Otherwise, the expressions are expanded immediately in an
expression context.}
@item{A @scheme[begin] form: The sub-forms of the @scheme[begin] are
spliced into the internal-definition sequence, and partial
expansion continues with the first of the newly-spliced forms
(or the next form, if the @scheme[begin] had no sub-forms).}
}
@section[#:tag "mz:fully-expanded"]{Fully Expanded Programs}
A fully expanded program---that is, a parsed program---is represented
in the same way as an unparsed program: as a syntax-object. However, a
fully expanded program fits a specific grammar.
@schemegrammar*[
#:literals (#%expression module #%plain-module-begin begin provide
define-values define-syntaxes define-values-for-syntax
require require-for-syntax require-for-template
#%plain-lambda case-lambda if begin begin0 let-values letrec-values
set! quote-syntax quote with-continuation-mark
#%plain-app #%datum #%top #%variable-reference)
[top-level-form general-top-level-form
(#%expression expr)
(module id name-id
(#%plain-module-begin
module-level-form ...))
(begin top-level-form ...)]
[module-level-form general-top-level-form
(provide provide-spec ...)]
[general-top-level-form expr
(define-values (id ...) expr)
(define-syntaxes (id ...) expr)
(define-values-for-syntax (id ...) expr)
(require require-spec ...)
(require-for-syntax require-spec ...)
(require-for-template require-spec ...)]
[expr id
(#%plain-lambda formals expr ...+)
(case-lambda (formals expr ...+) ...)
(if expr expr)
(if expr expr expr)
(begin expr ...+)
(begin0 expr expr ...)
(let-values (((id ...) expr) ...)
expr ...+)
(letrec-values (((id ...) expr) ...)
expr ...+)
(set! id expr)
(#, @scheme[quote] datum)
(quote-syntax datum)
(with-continuation-mark expr expr expr)
(#%plain-app expr ...+)
(#%datum . datum)
(#%top . id)
(#%variable-reference id)
(#%variable-reference (#%top . id))]
[formals (id ...)
(id ...+ . id)
id]]
@title{Macros}

View File

@ -23,9 +23,11 @@
@define[(*state c e) (make-element #f (list langle c comma e rangle))]
@define-syntax[state (syntax-rules ()
[(_ a b) (*state (scheme a) (scheme b))])]
@define[(frame n) (make-element "schemevariable"
(list "C" (make-element 'subscript (list (format "~a" n)))))]
@;------------------------------------------------------------------------
@title{Language Model}
@title{Evaluation Model}
Scheme evaluation can be viewed as the simplification of expressions
to obtain values. For example, just as an elementary-school student
@ -41,12 +43,12 @@ Scheme evaluation simplifies
The arrow @reduces above replaces the more traditional @tt{=} to
emphasize that evaluation proceeds in a particular direction towards
simpler expressions. In particular, a @defterm{value} is an
simpler expressions. In particular, a @deftech{value} is an
expression that evaluation simplifies no further, such as the number
@scheme[2].
@;------------------------------------------------------------------------
@section{Sub-expression Evaluation}
@section{Sub-expression Evaluation and Continuations}
Some simplifications require more than one step. For example:
@ -54,14 +56,14 @@ Some simplifications require more than one step. For example:
(- 4 #,(redex (+ 1 1))) #,reduces #,(redex (- 4 2)) #,reduces 2
]
An expression that is not a value can always be partitioned into two
parts: a @defterm{redex}, which is the part that changed in a
An expression that is not a @tech{value} can always be partitioned
into two parts: a @deftech{redex}, which is the part that changed in a
single-step simplification (show in blue), and the
@defterm{continuation}, which is the surrounding expression
@deftech{continuation}, which is the surrounding expression
context. In @scheme[(- 4 (+ 1 1))], the redex is @scheme[(+ 1 1)], and
the continuation is @scheme[(- 4 #, @hole)], where @hole takes the
place of the redex. That is, the continuation says how to ``continue''
after the redex is reduced to a value.
after the @tech{redex} is reduced to a @tech{value}.
Before some things can be evaluated, some sub-expressions must be
evaluated; for example, in the application @scheme[(- 4 (+ 1 1))], the
@ -72,69 +74,72 @@ Thus, the specification of each syntactic form specifies how (some of)
its sub-expressions are evaluated, and then how the results are
combined to reduce the form away.
The @defterm{dynamic extent} of an expression is the sequence of
evaluation steps during which an expression contains the redex.
The @deftech{dynamic extent} of an expression is the sequence of
evaluation steps during which an expression contains the @tech{redex}.
@;------------------------------------------------------------------------
@section{Tail Position}
An expression @scheme[_expr1] is in @defterm{tail position} with
An expression @scheme[_expr1] is in @deftech{tail position} with
respect to an enclosing expression @scheme[_expr2] if, whenever
@scheme[_expr1] becomes a redex, its continuation is the same as was
the enclosing @scheme[_expr2]'s continuation.
@scheme[_expr1] becomes a redex, its @tech{continuation} is the same
as was the enclosing @scheme[_expr2]'s @tech{continuation}.
For example, the @scheme[(+ 1 1)] expression is @italic{not} in tail
position with respect to @scheme[(- 4 (+ 1 1))]. To illustrate, we use
For example, the @scheme[(+ 1 1)] expression is @italic{not} in @tech{tail
position} with respect to @scheme[(- 4 (+ 1 1))]. To illustrate, we use
the notation @sub[_C _expr] to mean the expression that is produced by
substituing @scheme[_expr] in place of @hole in the continuation
substituting @scheme[_expr] in place of @hole in the @tech{continuation}
@scheme[_C]:
@schemeblock[
#, @sub[_C (- 4 (+ 1 1))] #, @reduces #, @sub[_C (- 4 2)]
]
In this case, the continuation for reducing @scheme[(+ 1 1)] is @sub[_C (+
4 #, @hole)], not just @scheme[_C].
In this case, the @tech{continuation} for reducing @scheme[(+ 1 1)] is
@sub[_C (+ 4 #, @hole)], not just @scheme[_C].
In contrast, @scheme[(+ 1 1)] is in tail position with respect to
@scheme[(if (zero? 0) (+ 1 1) 3)], because, for any continuation @scheme[_C],
In contrast, @scheme[(+ 1 1)] is in @tech{tail position} with respect
to @scheme[(if (zero? 0) (+ 1 1) 3)], because, for any continuation
@scheme[_C],
@schemeblock[
#, @sub[_C (if (zero? 0) (+ 1 1) 3)] #, @reduces #, @sub[_C (if #t (+ 1 1) 3)] #, @reduces #, @sub[_C (+ 1 1)]
]
The steps in this reduction sequence are driven by the definition of
@scheme[if], and they do not depend on the continuation
@scheme[if], and they do not depend on the @tech{continuation}
@scheme[_C]. The ``then'' branch of an @scheme[if] form is always in
tail position with respect to the @scheme[if] form. Due to a similar
reduction rule for @scheme[if] and @scheme[#f], the ``else'' branch of
an @scheme[if] form is also in tail position.
@tech{tail position} with respect to the @scheme[if] form. Due to a
similar reduction rule for @scheme[if] and @scheme[#f], the ``else''
branch of an @scheme[if] form is also in @tech{tail position}.
Tail-position specifications provide a guarantee about the asymtotic
space consumption of a computation. In general, the specification of
tail positions goes with each syntactic form, like @scheme[if].
@tech{Tail-position} specifications provide a guarantee about the
asymptotic space consumption of a computation. In general, the
specification of @tech{tail positions} goes with each syntactic form,
like @scheme[if].
@;------------------------------------------------------------------------
@section{Multiple Return Values}
A Scheme expression can evaluate to @defterm{multiple values}, in the
A Scheme expression can evaluate to @deftech{multiple values}, in the
same way that a procedure can accept multiple arguments.
Most continuations expect a particular number of result values.
Indeed, most continuations, such as @scheme[(+ #, @hole 1)] expect a
single value. The continuation @scheme[(let-values ([(x y) #, @hole])
_expr)] expects two result values; the first result replaces
@scheme[x] in the body @scheme[_expr], and the second replaces
@scheme[y] in @scheme[_expr]. The continuation @scheme[(begin #, @hole
(+ 1 2))] accepts any number of result values, because it ignores the
result(s).
Most @tech{continuations} expect a particular number of result
@tech{values}. Indeed, most @tech{continuations}, such as @scheme[(+
#, @hole 1)] expect a single @tech{value}. The @tech{continuation}
@scheme[(let-values ([(x y) #, @hole]) _expr)] expects two result
@tech{values}; the first result replaces @scheme[x] in the body
@scheme[_expr], and the second replaces @scheme[y] in
@scheme[_expr]. The @tech{continuation} @scheme[(begin #, @hole (+ 1
2))] accepts any number of result @tech{values}, because it ignores
the result(s).
In general, the specification of a syntactic form inidicates the
number of values that it produces and the number that it expects from
each of its sub-expression. In addtion, some procedures (notably
@scheme[values]) produce multiple values, and some procedures (notably
@scheme[call-with-values]) create continuations internally that accept
a certain number of values.
number of @tech{values} that it produces and the number that it
expects from each of its sub-expression. In addtion, some procedures
(notably @scheme[values]) produce multiple @tech{values}, and some
procedures (notably @scheme[call-with-values]) create continuations
internally that accept a certain number of @tech{values}.
@;------------------------------------------------------------------------
@section{Top-Level and Module-Level Variables}
@ -147,9 +152,9 @@ then an algebra student simplifies @tt{x + 1} as follows:
@verbatim{ x + 1 = 10 + 1 = 11}
Scheme works much the same way, in that a set of top-level variables
are available for substitutions on demand during evaluation. For
example, given
Scheme works much the same way, in that a set of @tech{top-level
variables} are available for substitutions on demand during
evaluation. For example, given
@schemeblock[
(define x 10)
@ -169,7 +174,7 @@ definitions in response to evaluating forms such as @scheme[define].
Each evaluation step, then, takes the current set of definitions and
program to a new set of definitions and program. Before a
@scheme[define] can be moved into the set of definitions, its
right-hand expression must be reduced to a value.
right-hand expression must be reduced to a @tech{value}.
@prog-steps/no-obj[
[{}
@ -191,7 +196,7 @@ a module is essentially a prefix on a defined name, so that different
modules can define the name.
Using @scheme[set!], a program can change the value associated with an
existing top-level variable:
existing @tech{top-level variable}:
@prog-steps/no-obj[
[{(define x 10)}
@ -207,26 +212,27 @@ existing top-level variable:
@;------------------------------------------------------------------------
@section{Objects and Imperative Update}
In addition to @scheme[set!] for imperative update of top-level
variables, various procedures enable the modification of elements
In addition to @scheme[set!] for imperative update of @tech{top-level
variables}, various procedures enable the modification of elements
within a compound data structure. For example, @scheme[vector-set!]
modifies the content of a vector.
To allow such modifications to data, we must distingiush between
values, which are the results of expressions, and @defterm{objects},
which hold the data referenced by a value.
@tech{values}, which are the results of expressions, and
@deftech{objects}, which hold the data referenced by a value.
A few kinds of objects can serve directly as values, including
A few kinds of @tech{objects} can serve directly as values, including
booleans, @scheme[(void)], and small exact integers. More generally,
however, a value is a reference to an object. For example, a value can
be a reference to a particular vector that currently holds the value
@scheme[10] in its first slot. If an object is modified, then the
modification is visible through all copies of the value that reference
the same object.
however, a @tech{value} is a reference to an @tech{object}. For
example, a @tech{value} can be a reference to a particular vector that
currently holds the value @scheme[10] in its first slot. If an
@tech{object} is modified, then the modification is visible through
all copies of the @tech{value} that reference the same @tech{object}.
In the evaluation model, a set of objects must be carried along with
each step in evaluation, just like the definition set. Operations that
create objects, such as @scheme[vector], add to the set of objects:
In the evaluation model, a set of @tech{objects} must be carried along
with each step in evaluation, just like the definition set. Operations
that create @tech{objects}, such as @scheme[vector], add to the set of
@tech{objects}:
@prog-steps[
[{}
@ -292,38 +298,39 @@ create objects, such as @scheme[vector], add to the set of objects:
11]
]
The distinction between a top-level variable is an object reference is
crucial. A top-level variable is not a value; each time a variable
expression is evaluated, the value is extracted from the current set
of definitions. An object reference, in contrast is a value, and
therefore needs no further evaluation. The model evaluation steps
above use angle-bracketed @scheme[<o1>] for an object reference to
distinguish it from a variable name.
The distinction between a @tech{top-level variable} and an object
reference is crucial. A @tech{top-level variable} is not a
@tech{value}; each time a @tech{variable} expression is evaluated, the
value is extracted from the current set of definitions. An object
reference, in contrast is a value, and therefore needs no further
evaluation. The model evaluation steps above use angle-bracketed
@scheme[<o1>] for an object reference to distinguish it from a
@tech{variable} name.
A direct object reference can never appear in a text-based source
program. A program representation created with
@scheme[datum->syntax-object], however, can embed direct references to
existing objects.
existing @tech{objects}.
@;------------------------------------------------------------------------
@section{Object Identity and Comparisons}
The @scheme[eq?] operator compares two values, returning @scheme[#t]
when the values refer to the same object. This form of equality is
suitable for comparing objects that support imperative update (e.g.,
to determine that the effect of modifying an object through one
reference is visible through another reference). Also, an @scheme[eq?]
test evaluates quickly, and @scheme[eq?]-based hashing is more
lightweight than @scheme[equal?]-based hashing in hash tables.
The @scheme[eq?] operator compares two @tech{values}, returning
@scheme[#t] when the values refer to the same @tech{object}. This form
of equality is suitable for comparing objects that support imperative
update (e.g., to determine that the effect of modifying an object
through one reference is visible through another reference). Also, an
@scheme[eq?] test evaluates quickly, and @scheme[eq?]-based hashing
is more lightweight than @scheme[equal?]-based hashing in hash tables.
In some cases, however, @scheme[eq?] is unsuitable as a comparison
operator, because the generation of objects is not clearly defined. In
particular, two applications of @scheme[+] to the same two exact
integers may or may not produce results that are @scheme[eq?],
operator, because the generation of @tech{objects} is not clearly
defined. In particular, two applications of @scheme[+] to the same two
exact integers may or may not produce results that are @scheme[eq?],
although the results are always @scheme[equal?]. Similarly, evaluation
of a @scheme[lambda] form typically generates a new procedure object,
but it may re-use a procedure object previously generated by the same
source @scheme[lambda] form.
of a @scheme[lambda] form typically generates a new procedure
@tech{object}, but it may re-use a procedure @tech{object} previously
generated by the same source @scheme[lambda] form.
The behavior of a datatype with respect to @scheme[eq?] is generally
specified with the datatype and its associated procedures.
@ -342,16 +349,17 @@ In the program state
evaluation cannot depend on @scheme[<o2>], because it is not part of
the program to evaluate, and it is not referenced by any definition
that is accessible in the program. The object @scheme[<o2>] may
therefore be removed from the evaluation by @defterm{garbage
that is accessible in the program. The @tech{object} @scheme[<o2>] may
therefore be removed from the evaluation by @deftech{garbage
collection}.
A few special compound datatypes hold @defterm{weak references} to
objects. Such weak references are treated specialy by the garbage
collector in determining which objects are reachable for the remainder
of the computation. If an object is reachable only via a weak
reference, then the object can be reclaimed, and the weak reference is
replaced by a different value (typically @scheme[#f]).
A few special compound datatypes hold @deftech{weak references} to
objects. Such weak references are treated specially by the garbage
collector in determining which @tech{objects} are reachable for the
remainder of the computation. If an @tech{object} is reachable only
via a @tech{weak reference}, then the object can be reclaimed, and the
@tech{weak reference} is replaced by a different @tech{value}
(typically @scheme[#f]).
@;------------------------------------------------------------------------
@section{Procedure Applications and Local Bindings}
@ -365,11 +373,12 @@ then an algebra student simplifies @tt{f(1)} as follows:
@verbatim{ f(7) = 7 + 10 = 17}
The key step in this simplification is take the body of the defined
function @tt{f}, and then replace each @tt{x} with the actual value
@tt{1}.
function @tt{f}, and then replace each @tt{x} with the actual
@tech{value} @tt{1}.
Scheme procedure application works much the same way. A procedure is
an object, so evaluating @scheme[(f 7)] starts with a variable lookup:
an @tech{object}, so evaluating @scheme[(f 7)] starts with a
@tech{variable} lookup:
@prog-steps[
[{(define <p1> (lambda (x) (+ x 10)))}
@ -380,16 +389,17 @@ an object, so evaluating @scheme[(f 7)] starts with a variable lookup:
(code:hilite (<p1> 7))]
]
Unlike in algebra, however, the value associated with an argument can
be changed in the body of a procedure by using @scheme[set!], as in
the example @scheme[(lambda (x) (begin (set! x 3) x))]. Since the value
associated with @scheme[x] can be changed, an actual value for cannot
be substituted for @scheme[x] when the procedure is applied.
Unlike in algebra, however, the @tech{value} associated with an
argument can be changed in the body of a procedure by using
@scheme[set!], as in the example @scheme[(lambda (x) (begin (set! x 3)
x))]. Since the @tech{value} associated with @scheme[x] can be
changed, an actual value for cannot be substituted for @scheme[x] when
the procedure is applied.
Instead, a new @defterm{location} is created for each variable on each
application. The argument value is placed in the location, and each
insteace of the variable in the procedure body is replaced with the
new location:
Instead, a new @deftech{location} is created for each @tech{variable}
on each application. The argument @tech{value} is placed in the
@tech{location}, and each instance of the @tech{variable} in the
procedure body is replaced with the new @tech{location}:
@prog-steps[
[{(define <p1> (lambda (x) (+ x 10)))}
@ -409,14 +419,16 @@ new location:
17]
]
A location is the same as a top-level variable, but when a location is
generated, it (conceptually) uses a name that has not been used before
and that cannot not be generated again or accessed directly.
A @tech{location} is the same as a @tech{top-level variable}, but when
a @tech{location} is generated, it (conceptually) uses a name that has
not been used before and that cannot not be generated again or
accessed directly.
Generating a location in this way means that @scheme[set!] evaluates
for local variables in the same way as for top-level variables,
because the local variable is always replaced with a location by the
time the @scheme[set!] form is evaluated:
Generating a @tech{location} in this way means that @scheme[set!]
evaluates for @tech{local variables} in the same way as for
@tech{top-level variables}, because the @tech{local variable} is
always replaced with a @tech{location} by the time the @scheme[set!]
form is evaluated:
@prog-steps[
[{(define <p1> (lambda (x) (begin (set! x 3) x)))}
@ -443,138 +455,85 @@ time the @scheme[set!] form is evaluated:
3]
]
The substition and location-generation step of procedure application
requires that the argument is a value. Therefore, in @scheme[((lambda
(x) (+ x 10)) (+ 1 2))], the @scheme[(+ 1 2)] sub-expression must be
simplified to the value @scheme[3], and then @scheme[3] can be placed
into a location for @scheme[x]. In other words, Scheme is a
@defterm{call-by-value} language.
The substition and @tech{location}-generation step of procedure
application requires that the argument is a @tech{value}. Therefore,
in @scheme[((lambda (x) (+ x 10)) (+ 1 2))], the @scheme[(+ 1 2)]
sub-expression must be simplified to the @tech{value} @scheme[3], and
then @scheme[3] can be placed into a @tech{location} for
@scheme[x]. In other words, Scheme is a @deftech{call-by-value}
language.
Evaluation of a local binding, such as @scheme[(let ([x (+ 1 2)])
_expr)], is the same as for a procedure call. After @scheme[(+ 1 2)]
produces a value, it is stored in a fresh location that replaces every
instance of @scheme[x] in @scheme[_expr].
produces a @tech{value}, it is stored in a fresh @tech{location} that
replaces every instance of @scheme[x] in @scheme[_expr].
@;------------------------------------------------------------------------
@section{Identifiers, Variables, and Locations}
@section{Variables and Locations}
A @defterm{variable} is a placeholder for a value, and an expressions
in an initial program refer to variables. A top-level variable is both
a variable and a location. Any other variable is always replaced by a
location at run-time, so that evaluation of expressions involves only
locations. A single non-top-level variable, such as a procedure
argument, can correspond to different locations at different times.
A @deftech{variable} is a placeholder for a @tech{value}, and an
expressions in an initial program refer to @tech{variables}. A
@deftech{top-level variable} is both a @tech{variable} and a
@tech{location}. Any other @tech{variable} is always replaced by a
@tech{location} at run-time, so that evaluation of expressions
involves only @tech{locations}. A single @deftech{local variable}
(i.e., a non-top-level, non-module-level @tech{variable}), such as a
procedure argument, can correspond to different @tech{locations}
through different instantiations.
The replacement of a variable with a location during evaluation
implements Scheme's @defterm{lexical scoping}. For example, when the
procedure-argument variable @scheme[x] is replaced by the location
@scheme[xloc], then it is replaced throughout the body of the
procedure, including with any nested @scheme[lambda] forms. As a
result, future references of the variable always access the same
location.
For example, in the program
@guideintro["guide:binding"]{binding}
@schemeblock[(define y (+ (let ([x 5]) x) 6))]
An @defterm{identifier} is source-program entity. Parsing a Scheme
program reveals that some identifiers correspond to variables, some
refer to syntactic forms, and some are quoted to produce a symbol or a
syntax object. An identifier @defterm{binds} another when the former is
parsed as a variable and the latter is parsed as a reference to the
former. An identifier is @defterm{bound} in a sub-expression if it
binds any uses of the identifier in the sub-expression that are not
otherwise bound within the sub-expression; conversely, a binding for a
sub-expression @defterm{shadows} any bindings in its context, so that
uses of an identifier refer to the shaodowing binding.
both @scheme[y] and @scheme[x] are @tech{variables}. The @scheme[y]
@tech{variable} is a @tech{top-level variable}, and the @scheme[x] is
a @tech{local variable}. When this code is evaluated, a
@tech{location} is created for @scheme[x] to hold the value
@scheme[5], and a @tech{location} is also created for @scheme[y] to
hold the value @scheme[6].
Throughout the documentation, identifiers are typeset to suggest the
way that they are parsed. A black, boldface identifier like
@scheme[lambda] indicates as a reference to a syntactic form. A plain
blue identifer like @schemeidfont{x} is a variable or a reference to
an unspecified top-level definition. A hyperlinked identifier
@scheme[cons] is a reference to a specific top-level definition.
The replacement of a @tech{variable} with a @tech{location} during
evaluation implements Scheme's @deftech{lexical scoping}. For example,
when a procedure-argument @tech{variable} @scheme[x] is replaced by
the @tech{location} @scheme[xloc], then it is replaced throughout the
body of the procedure, including with any nested @scheme[lambda]
forms. As a result, future references of the @tech{variable} always
access the same @tech{location}.
@;------------------------------------------------------------------------
@section{Parsing and Compilation}
@section{Continuation Frames and Marks}
The syntax of a Scheme program is defined by
Every continuation @scheme[_C] can be partitioned into
@deftech{continuation frames} @frame[1], @frame[2], ..., @frame["n"]
such that @scheme[_C] = @*sub[@frame[1] @*sub[@frame[2] @*sub["..."
@frame["n"]]]], and no frame @frame["i"] can be itself partitioned
into smaller continuations. Evaluation steps add an remove frames to
the current continuation, typically one at a time.
@itemize{
@item{a @defterm{read} phase that processes a character stream into a
Scheme value, especially one composed of pairs and symbols,
and}
@item{an @defterm{expand} phase that processes the value to finish
parsing the code.}
}
For details on the read phase, see @secref["mz:reader"]. Source code
is normally read in @scheme[read-syntax] mode, otherwise it must be
converted to syntax using @scheme[datum->syntax]; the expand phase is
defined in terms of syntax objects.
An identifier, for example, is a syntax-object symbol, and the
identifier's binding is determined by lexical information attached to
the identifier. Expansion recursively processes a syntax object,
both using its lexical information and extending the information for
nested objects. For details, see @secref["mz:expansion"].
Ultimately, expansion produces a syntax object matching the grammar
of the forms in @secref["mz:fully-expanded"]. This fully-expanded
datum corresponds to a parsed expression, and lexical information on
its identifiers indicates the parse. For example, a @scheme[car]
identifier might have lexical information that designates it as the
@scheme[car] from the @schememodname[big] language (i.e., the built-in
@scheme[car]). Similarly, a @scheme[lambda] identifier's lexical
information may indicate that it represents a procedure form.
Each frame is conceptually annotated with a set of
@deftech{continuation marks}. A mark consists of a key and its value;
the key is an arbitrary value, and each frame includes at most one
mark for any key. Various operations set and extract marks from
continuations, so that marks can be used to attach information to a
dynamic extent. For example, marks can be used to record information
for a ``stack trace'' to be used when an exception is raised, or
implement dynamically scoped bindings.
@;------------------------------------------------------------------------
@section{Namespaces}
@section{Prompts and Delimited Continuations}
A @idefterm{namespace} is a top-level mapping from symbols to binding
information. It is the starting point for expanding an expression; a
syntax object produced by @scheme[read-syntax] has no initial
lexical context; the syntax object can be expanded after
initializing it with the mappings of a particular namespace.
A namespace maps each symbol to one of three possible bindings:
@itemize{
@item{a particular module-level binding from a particular module}
@item{a top-level transformer binding named by the symbol}
@item{a top-level variable named by the symbol}
}
An ``empty'' namespace maps all symbols to top-level
variables. Importing a module into the top-level adjusts the namespace
bindings for all of the imported named. Evaluating a top-level
@scheme[define] form updates the namespace's mapping to refer to a
variable (if it does not already) and installs a value into the
variable.
In addition to its main mapping, each namespace encapsulates a
distinct set of top-level variables, as well as a potentially distinct
set of module instances. After a namespace is created, module
instances from existing namespaces can be attached to the new
namespace.
At all times during evaluation, some namespace is designated as the
@defterm{current namespace}. The current namespace has no particular
relationship, however, with the namespace used to expand the code that
is executing. Furthermore, a namespace is purely a top-level concept;
it does not encapsulate the full environment of an expression within
local binding forms.
In terms of the evaluation model, top-level variables from different
namespaces essentially correspond to definitions with different
prefixes. In particular, changing the current namespace during
evaluation does not change the variables to which executing
expressions refer.
A @deftech{prompt} is a special kind of continuation frame that is
annotated with a specific @deftech{prompt-tag} (essentially a
continuation mark). Various operations allow the capture of frames in
the continuation from the redex position out to the nearest enclosing
prompt with a particular prompt tag; such a continuation is sometimes
called a @deftech{delimited continuation}. Other operations allow the
current continuation to be extended with a captured continuation
(specifically, a @deftech{composable continuation}). Yet other
operations abort the computation to the nearest enclosing prompt with
a particular tag, or replace the continuation to the nearest enclosing
prompt with another one. When a delimited continuation is captured,
the marks associated with the relevant frames are also captured.
@;------------------------------------------------------------------------
@section{Threads}
@ -588,8 +547,64 @@ state. Most evaluation steps involve a single step in a single
expression, but certain synchronization primitives require multiple
threads to progress together in one step.
In addition to shared state, each thread has its own private state
that is accessed through @defterm{thread cells} and
@defterm{parameters}. In particular, the current namespace is a
thread-specific property implemented by a parameter; it is not a
global property.
In addition to the state that is shared among all threads, each thread
has its own private state that is accessed through @deftech{thread
cells}. A thread cell is similar to a normal mutable object, but a
change to the value inside a thread cell is seen only when extracting
a value from the cell from the same thread. A thread cell can be
@deftech{preserved}; when a new thread is created, the creating
thread's value for a preserved thread cell serves as the initial value
for the cell in the created thread. For a non-preserved thread cell, a
new thread sees the same initial value (specified when the thread cell
is created) as all other threads.
@;------------------------------------------------------------------------
@section{Parameters}
A @deftech{parameter} is essentially a derived concept in Scheme; they
are defined in terms of continuation marks and thread cells. However,
parameters are also built in, in the sense that some primitive
procedures consult parameter values. For example, the default output
stream for primitive output operations is determined by a parameter.
A parameter is a setting that is both thread-specific and
continuation-specific. In the empty continuation, each parameter
corresponds to a preserved thread cell; a corresponding
@deftech{parameter procedure} accesses and sets the thread cell's
value for the current thread.
In a non-empty continuation, a parameter's value is determined through
a @deftech{parameterization} that is associated with the nearest
enclosing continuation frame though a continuation mark (whose key is
not directly accessible). A parameterization maps each parameter to a
preserved thread cell, and the combination of thread cell and current
thread yields the parameter's value. A parameter procedure sets or
accesses the relevant thread cell for its parameter.
Various operations, such as @scheme[parameterize] or
@scheme[with-parameterization], install a parameterization into the
current continuation's frame.
@;------------------------------------------------------------------------
@section{Exceptions}
@deftech{Exceptions} are essentially a derived concept in Scheme; they
are defined in terms of continuations, prompts, and continuation
marks. However, exceptions are also built in, in the sense that
primitive forms and procedures may raise exceptions.
A handler for uncaught exceptions is designated through a built-in
parameter. A handler to catch exceptions can be associated with a
continuation frame though a continuation mark (whose key is not
directly accessible). When an exception is raised, the current
continuation's marks determine a chain of handler procedures that are
consulted to handle the exception.
One potential action of an exception handler is to abort the current
continuation up to an enclosing prompt with a particular tag. The
default handler for uncaught exceptions, in particular, aborts to a
particular tag for which a prompt is always present, because the
prompt is installed in the outermost frame of the continuation for any
new thread.

View File

@ -22,19 +22,20 @@ through a @seclink["mz:readtables"]{readtable} and various other
@seclink["parameters"]{parameters}. This section describes the reader's
parsing when using the default readtable.
Reading from a stream produces one datum. If the result datum is a
compound value, then reading the datum typically requires the reader
to call itself recursively to read the component data.
Reading from a stream produces one @defterm{datum}. If the result
datum is a compound value, then reading the datum typically requires
the reader to call itself recursively to read the component data.
The reader can be invoked in either of two modes: @scheme[read] mode,
or @scheme[read-syntax] mode. In @scheme[read-syntax] mode, the result
is always a @seclink["stxobj"]{syntax object} that includes
source-location information wrapped around the sort of datum that
@scheme[read] mode would produce. In the case of pairs, vectors, and
boxes, morever, the content is also wrapped recursively as a syntax
object. Unless specified otherwise, this section describes the
reader's behavior in @scheme[read] mode, and @scheme[read-syntax] mode
does the same modulo wrapping the final result.
source-location and (initially empty) lexical information wrapped
around the sort of datum that @scheme[read] mode would produce. In the
case of pairs, vectors, and boxes, morever, the content is also
wrapped recursively as a syntax object. Unless specified otherwise,
this section describes the reader's behavior in @scheme[read] mode,
and @scheme[read-syntax] mode does the same modulo wrapping the final
result.
Reading is defined in terms of Unicode characters; see
@secref["mz:char-input"] for information on how a byte stream is converted

View File

@ -12,8 +12,8 @@ language.
@table-of-contents[]
@include-section["model.scrbl"]
@include-section["syntax-model.scrbl"]
@include-section["read.scrbl"]
@include-section["macros.scrbl"]
@include-section["syntax.scrbl"]
@include-section["derived.scrbl"]
@include-section["data.scrbl"]
@ -22,7 +22,7 @@ language.
@section["Input and Output"]
@subsection[#:tag "mz:char-input"]{Form Bytes to Characters}
@subsection[#:tag "mz:char-input"]{From Bytes to Characters}
@;------------------------------------------------------------------------

View File

@ -0,0 +1,423 @@
#reader(lib "docreader.ss" "scribble")
@require[(lib "struct.ss" "scribble")]
@require-for-syntax[mzscheme]
@require["mz.ss"]
@;------------------------------------------------------------------------
@title{Syntax Model}
The syntax of a Scheme program is defined by
@itemize{
@item{a @deftech{read} phase that processes a character stream into a
Scheme value, especially one composed of pairs and symbols, and
possibly with source-location information to form a
@tech{syntax object}; and}
@item{an @deftech{expand} phase that processes a syntax object to
produce one that is fully parsed.}
}
For details on the @tech{read} phase, see @secref["mz:reader"]. Source
code is normally read in @scheme[read-syntax] mode. Otherwise, it must
be converted to syntax using @scheme[datum->syntax], because the
@tech{expand} phase is defined in terms of @tech{syntax objects}.
Expansion recursively processes a @tech{syntax object}. Binding
information on a syntax object drives the expansion process, and the
expansion process generates new syntax objects that are like old ones,
but enriched with new binding information.
@;------------------------------------------------------------------------
@section{Identifiers and Binding}
@guideintro["guide:binding"]{binding}
An @deftech{identifier} is source-program entity. Parsing a Scheme
program reveals that some @tech{identifiers} correspond to
@tech{variables}, some refer to syntactic forms, and some are quoted
to produce a symbol or a syntax object. An identifier @deftech{binds}
another (i.e., it is a @deftech{binding}) when the former is parsed as
a @tech{variable} and the latter is parsed as a reference to the
former. An @tech{identifier} is @deftech{bound} in a sub-expression if
it @tech{binds} any uses of the @tech{identifier} in the
sub-expression that are not otherwise @tech{bound} within the
sub-expression; conversely, a binding for a sub-expression
@deftech{shadows} any @tech{bindings} (i.e., it is
@deftech{shadowing}) in its context, so that uses of an
@tech{identifier} refer to the @tech{shadowing} @tech{binding}. The
@deftech{environment} of a form is the set of bindings whose scope
includes the form.
For example, as a bit of source, the text
@schemeblock[(let ([x 5]) x)]
includes two @tech{identifiers}: @scheme[let] and @scheme[x] (which
appears twice). When this source is parsed in a typical
@tech{environment}, @scheme[x] turns out to represent a
@tech{variable} (unlike @scheme[let]). In particular, the first
@scheme[x] @tech{binds} the second @scheme[x].
Throughout the documentation, @tech{identifiers} are typeset to
suggest the way that they are parsed. A black, boldface
@tech{identifier} like @scheme[lambda] indicates as a reference to a
syntactic form. A plain blue @tech{identifier} like @schemeidfont{x}
is a @tech{variable} or a reference to an unspecified @tech{top-level
variable}. A hyperlinked @tech{identifier} @scheme[cons] is a
reference to a specific @tech{top-level variable}.
@;------------------------------------------------------------------------
@section{Syntax Objects}
A @deftech{syntax object} combines a simpler Scheme value, such as a
symbol or pair, which information about bindings and (optionally)
source-location information. In particular, an @tech{identifier} is
represented as a symbol object that combines a symbol and
lexical/source information.
For example, a @schemeidfont{car} @tech{identifier} might have lexical
information that designates it as the @scheme[car] from the
@schememodname[big] language (i.e., the built-in
@scheme[car]). Similarly, a @schemeidfont{lambda} identifier's lexical
information may indicate that it represents a procedure form. Some
other @tech{identifier}'s lexical information may indicate that it
references a @tech{top-level variable}.
When a @tech{syntax object} represents a more complex expression than
am identifier or simple constant, its internal pieces can be
extracted. Detailed information about binding is available mostly
indirectly. For example, two identifiers, perhaps extracted from a
larger expression, can be compared to see if they refer to the same
binding (i.e., @scheme[free-identifier=?]). A slightly different test
is whether each identifier would bind the other if one was in a
binding position and the other in an expression position (i.e.,
@scheme[bound-identifier=?]).
For example, the when the program written as
@schemeblock[(let ([x 5]) (+ x 6))]
is represented as a syntax object, then two @tech{syntax objects} can
be extracted for the two @scheme[x]s. Both the
@scheme[free-identifier=?] and @scheme[bound-identifier=?] predicates
will indicate that the @scheme[x]s are the same. In contrast, the
@scheme[let] identifier is not @scheme[free-identifier=?] or
@scheme[bound-identifier=?] to either @scheme[x].
The lexical information in a syntax object is independent of the other
half, and it can be transferred to a new syntax object, combined with
an arbitrary other Scheme value. Thus, identifier-binding information
in a syntax object is predicated on the symbolic name of the
identifier; the same question with the same lexical information but
different base value can produce a different answer.
For example, combining the lexical information from @scheme[let] in
the program above to @scheme['x] would not produce an identifier that
is @scheme[free-identifier=?] to either @scheme[x], since it does not
appear in the scope of the @scheme[x] binding. Combining the lexical
context of the @scheme[6] with @scheme['x], in contrast, would produce
an identifier that is @scheme[bound-identifier=?] to both @scheme[x]s.
The @scheme[quote-syntax] form bridges the evaluation of a program and
the representation of a program. Specifically, @scheme[(quote-syntax
_datum)] produces a syntax object that preserves all of the lexical
information that @scheme[_datum] had when it was parsed as part of a
@scheme[quote-syntax] form.
@;------------------------------------------------------------------------
@section[#:tag "mz:expansion"]{Expansion@aux-elem{ (Parsing)}}
Expansion recursively processes a @tech{syntax object}. Binding
information on a syntax object drives the expansion process, and the
expansion process generates new syntax objects that are like old ones,
but enriched with new binding information.
@;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@subsection[#:tag "mz:fully-expanded"]{Fully Expanded Programs}
A complete expansion produces a @tech{syntax object} matching the
following grammar:
@schemegrammar*[
#:literals (#%expression module #%plain-module-begin begin provide
define-values define-syntaxes define-values-for-syntax
require require-for-syntax require-for-template
#%plain-lambda case-lambda if begin begin0 let-values letrec-values
set! quote-syntax quote with-continuation-mark
#%plain-app #%datum #%top #%variable-reference)
[top-level-form general-top-level-form
(#%expression expr)
(module id name-id
(#%plain-module-begin
module-level-form ...))
(begin top-level-form ...)]
[module-level-form general-top-level-form
(provide provide-spec ...)]
[general-top-level-form expr
(define-values (id ...) expr)
(define-syntaxes (id ...) expr)
(define-values-for-syntax (id ...) expr)
(require require-spec ...)
(require-for-syntax require-spec ...)
(require-for-template require-spec ...)]
[expr id
(#%plain-lambda formals expr ...+)
(case-lambda (formals expr ...+) ...)
(if expr expr)
(if expr expr expr)
(begin expr ...+)
(begin0 expr expr ...)
(let-values (((id ...) expr) ...)
expr ...+)
(letrec-values (((id ...) expr) ...)
expr ...+)
(set! id expr)
(#, @scheme[quote] datum)
(quote-syntax datum)
(with-continuation-mark expr expr expr)
(#%plain-app expr ...+)
(#%top . id)
(#%variable-reference id)
(#%variable-reference (#%top . id))]
[formals (id ...)
(id ...+ . id)
id]]
This fully-expanded @tech{syntax object} corresponds to a
@deftech{parse} of the expression (i.e., a @deftech{parsed}
expression), and lexical information on its @tech{identifiers}
indicates the @tech{parse}.
@;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@subsection{Expansion Steps}
A step in parsing a form represented as a syntax object depends on its
outermost shape:
@itemize{
@item{If it is an @tech{identifier} (i.e., a syntax-object symbol), then a
binding is determined using symbol along with the lexical
information in the identifier. If the identifier has a binding
other than as a top-level variable, it is used to continue. If
the identifier has no binding, a new syntax-object symbol
@scheme['#%top] is created using the lexical context of the
identifier; if this @schemeidfont{#%top} identifier has no
binding (other than as a top-level variable), then parsing
fails with an @scheme[exn:fail:syntax] exception. Otherwise,
the new identifier is combined with the original identifier in
a new syntax-object pair (using the same context as the
original identifier), and the @schemeidfont{#%top} binding is
used to continue.}
@item{If it is a syntax-object pair whose first element is an
identifier, and if the identifier has a binding other than as a
top-level variable, then the identifier's binding is used to
continue.}
@item{If it is a syntax-object pair of any other form, then a new
syntax-object symbol @scheme['#%app] is created using the
lexical context of the pair. If the resulting
@schemeidfont{#%app} identifier has no binding, parsing fails
with an @scheme[exn:fail:syntax] exception. Otherwise, the new
identifier is combined with the original pair to form a new
syntax-object pair (using the same context as the original
pair), and the @schemeidfont{#%app} binding is used to
continue.}
@item{If it is any other syntax object, then a new syntax-object
symbol @scheme['#%datum] is created using the lexical context
of the original syntax object. If the resulting
@schemeidfont{#%datum} identifier has no binding, parsing fails
with an @scheme[exn:fail:syntax] exception. Otherwise, the new
identifier is combined with the original syntax object in a new
syntax-object pair (using the same context as the original
pair), and the @schemeidfont{#%datum} binding is used to
continue.}
}
Thus, the possibilities that do not fail lead to an identifier with a
particular binding. This binding refers to one of three things:
@itemize{
@item{A transformer binding, such as introduced by
@scheme[define-syntax] or @scheme[let-syntax]. If the
associated value is to a procedure of one argument, the
procedure is called as a syntax transformer (see
@secref["transformers"]), and parsing starts again with the
syntax-object result. If the transformer binding is to any
other kind of value, parsing fails with an
@scheme[exn:fail:syntax] exception.}
@item{A variable binding, such as introduced by a module-level
@scheme[define] or by @scheme[let]. In this case, if the form
being parsed is just an identifier, then it is parsed as a
run-time reference to the location of the corresponding
variable. If the form being parsed is a syntax-object list,
then an @scheme[#%app] is added to the front of the
syntax-object list in the same way as when the first item in
the syntax-object list is not an identifier (third case in the
previous enumeration), and parsing continues.}
@item{Core syntax, which is parsed as described in
@secref["mz:syntax"]. Parsing core syntactic forms typically
involves recursive parsing of sub-forms, and may introduce
bindings that control the parsing of sub-forms.}
}
Each expansion step occurs in a particular context, and transformers
and core-syntax parsing can depend on the context. For example, a
@scheme[module] form is allowed only in a top-level context. The
possible contexts are as follows:
@itemize{
@item{@defterm{top level} : outside of any module, definition, or
expression, except that sub-expressions of a top-level
@scheme[begin] form are also expanded as top-level forms.}
@item{@defterm{module begin} : inside the body of a module, as the
only form within the module.}
@item{@defterm{module body} : in the body of a module (inside the
moudule-begin layer).}
@item{@defterm{internal definition} : in a nested context that allows
both definitions and expressions.}
@item{@defterm{expression} : in a context where only expressions are
allowed.}
}
Different core syntax forms parse sub-forms in different contexts. For
example, a @scheme[let] form always parses the right-hand expressions
of a binding in an expression context, but it starts parsing the body
in an internal-definition context.
@;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@subsection[#:tag "mz:intdef-body"]{Internal Definitions}
An internal-definition context corresponds to a partial expansion
step. A form that supports internal definitions starts by expanding
its first form in an internal-definition context, but only
partially. That is, it recursively expands only until the form becomes
one of the following:
@itemize{
@item{A @scheme[define-values] or @scheme[define-syntaxes] form, for
any form other than the last one: The definition form is not
expanded further. Instead, the next form is expanded partially,
and so on. As soon as an expression form is found, the
accumulated definition forms are converted to a
@scheme[letrec-values] (if no @scheme[define-syntaxes] forms
were found) or @scheme[letrec-syntaxes+values] form, moving the
expression forms to the body to be expanded in expression
context.
When a @scheme[define-values] form is discovered, the lexical
context of all syntax objects for the body sequence is
immediately enriched with bindings for the
@scheme[define-values] form before expansion continues. When a
@scheme[define-syntaxes] form is discovered, the right-hand
side is executed and a transformer binding is installed for the
body sequence before expansion continues.}
@item{A primitive expression form other than @scheme[begin]: The
expression is expanded in an expression context, along with all
remaining body forms. If any definitions were found, this
expansion takes place after conversion to a
@scheme[letrec-values] or @scheme[letrec-syntaxes+values]
form. Otherwise, the expressions are expanded immediately.}
@item{A @scheme[begin] form: The sub-forms of the @scheme[begin] are
spliced into the internal-definition sequence, and partial
expansion continues with the first of the newly-spliced forms
(or the next form, if the @scheme[begin] had no sub-forms).}
}
If the last expression form turns out to be a @scheme[define-values]
or @scheme[define-syntaxes] form, expansion fails with a syntax error.
@;------------------------------------------------------------------------
@section{Compilation}
Before expanded code is evaluated, it is first @deftech{compiled}. A
compiled form has essentially the same information as the
corresponding expanded form, though the internal representation
naturally dispenses with identifiers for syntactic forms and local
bindings. One significant difference is that a compiled form is almost
entirely opaque, so the information that it contains cannot be
accessed directly (which is why some identifiers can be dropped). At
the same time, a compiled form can be marshaled to and from a byte
string, so it is suitable for saving and re-loading code.
Although individual read, expand, compile, and evaluate operations are
available, the operations are often combined automatically. For
example, the @scheme[eval] procedure takes a syntax object and expands
it, compiles it, and evaluates it.
@;------------------------------------------------------------------------
@section{Namespaces}
A @deftech{namespace} is a top-level mapping from symbols to binding
information. It is the starting point for expanding an expression; a
@tech{syntax object} produced by @scheme[read-syntax] has no initial
lexical context; the @tech{syntax object} can be expanded after
initializing it with the mappings of a particular namespace. A
namespace is also the starting point evaluating expanded code, where
the first step in evaluation is linking the code to specific module
instances and top-level variables.
For expansion purposes, a namespace maps each symbol to one of three
possible bindings:
@itemize{
@item{a particular module-level binding from a particular module}
@item{a top-level transformer binding named by the symbol}
@item{a top-level variable named by the symbol}
}
An ``empty'' namespace maps all symbols to top-level variables.
Certain evaluations extend a namespace for future expansions;
importing a module into the top-level adjusts the namespace bindings
for all of the imported named, and evaluating a top-level
@scheme[define] form updates the namespace's mapping to refer to a
variable (in addition to installing a value into the variable).
For evaluation, each namespace encapsulates a distinct set of
top-level variables, as well as a potentially distinct set of module
instances. After a namespace is created, module instances from
existing namespaces can be attached to the new namespace. In terms of
the evaluation model, top-level variables from different namespaces
essentially correspond to definitions with different prefixes.
Furthermore, the first step in evaluating any compiled expression is
to link its top-level variable and module-level variable references to
specific variables in the namespace.
At all times during evaluation, some namespace is designated as the
@deftech{current namespace}. The current namespace has no particular
relationship, however, with the namespace that was used to expand the
code that is executing, or with the namespace that was used to link
the compiled form of the currently evaluating code. In particular,
changing the current namespace during evaluation does not change the
variables to which executing expressions refer. The current namespace
only determines the behavior of (essentially reflective) operations to
expand code and to start evaluating expanded/compiled code.
A namespace is purely a top-level entity, not to be confused with an
environment. In particular, a namespace does not encapsulate the full
environment of an expression inside local-binding forms.

View File

@ -527,7 +527,7 @@ in tail position only if no @scheme[body]s are present.
]}
@;------------------------------------------------------------------------
@section{Continuation Marks: @scheme[with-continuation-marks]}
@section{Continuation Marks: @scheme[with-continuation-mark]}
@defform[(with-continuation-mark key-expr val-expr result-expr)]{
Evaluates @scheme[key-expr] and @scheme[val-expr] in order to obtain a key and