parent
60a6dc1796
commit
19d096dde7
|
@ -64,11 +64,11 @@ which is the part that can change in a
|
|||
single-step simplification (highlighted), and the
|
||||
@deftech{continuation}, which is the evaluation
|
||||
context surrounding the redex. In @racket[(- 4 (+ 1 1))], the redex is @racket[(+ 1 1)], and
|
||||
the continuation is @racket[(- 4 @#,hole)], where @hole indicates the
|
||||
position of the redex. That is, the continuation says how to ``continue''
|
||||
the continuation is @racket[(- 4 @#,hole)], where @hole takes the place
|
||||
of the @tech{redex} as it is reduced. That is, the continuation says how to ``continue''
|
||||
after the @tech{redex} is reduced to a @tech{value}.
|
||||
|
||||
Before some expressions can be evaluated, their sub-expressions must be
|
||||
Before some expressions can be evaluated, some or all of their sub-expressions must be
|
||||
evaluated. For example, in the application @racket[(- 4 (+ 1 1))], the
|
||||
application of @racket[-] cannot be reduced until the sub-expression
|
||||
@racket[(+ 1 1)] is reduced.
|
||||
|
@ -77,8 +77,7 @@ its sub-expressions are evaluated and then how the results are
|
|||
combined to reduce the form away.
|
||||
|
||||
The @deftech{dynamic extent} of an expression is the sequence of
|
||||
evaluation steps starting when the expression is selected as a @tech{redex}
|
||||
and continuing until it is fully evaluated.
|
||||
evaluation steps during which the expression contains the @tech{redex}.
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@section{Tail Position}
|
||||
|
@ -86,12 +85,12 @@ and continuing until it is fully evaluated.
|
|||
An expression @racket[_expr1] is in @deftech{tail position} with
|
||||
respect to an enclosing expression @racket[_expr2] if, whenever
|
||||
@racket[_expr1] becomes a redex, its @tech{continuation} is the same
|
||||
as the enclosing @racket[_expr2]'s @tech{continuation}.
|
||||
as was the enclosing @racket[_expr2]'s @tech{continuation}.
|
||||
|
||||
For example, the @racket[(+ 1 1)] expression is @italic{not} in @tech{tail
|
||||
position} with respect to @racket[(- 4 (+ 1 1))]. To illustrate, we use
|
||||
the notation @sub[_C _expr] to mean the expression that is produced by
|
||||
substituting @racket[_expr] in place of @hole in some arbitrary @tech{continuation}
|
||||
substituting @racket[_expr] in place of @hole in some @tech{continuation}
|
||||
@racket[_C]:
|
||||
|
||||
@racketblock[
|
||||
|
@ -125,8 +124,8 @@ each syntactic form, such as @racket[if].
|
|||
@;------------------------------------------------------------------------
|
||||
@section[#:tag "values-model"]{Multiple Return Values}
|
||||
|
||||
A Racket expression can evaluate to @deftech{multiple values}, similar
|
||||
to the way that a procedure can accept multiple arguments.
|
||||
A Racket expression can evaluate to @deftech{multiple values}, to
|
||||
provide symmetry with the fact that a procedure can accept multiple arguments.
|
||||
|
||||
Most @tech{continuations} expect a certain number of result
|
||||
@tech{values}, although some @tech{continuations} can accept
|
||||
|
@ -157,7 +156,7 @@ then an algebra student simplifies @tt{x + 1} as follows:
|
|||
|
||||
@verbatim{ x + 1 = 10 + 1 = 11}
|
||||
|
||||
Racket works much the same way, in that a set of @deftech{top-level
|
||||
Racket works much the same way, in that a set of @tech{top-level
|
||||
variables} (see also @secref["vars-and-locs"]) are available for substitutions on demand during
|
||||
evaluation. For example, given
|
||||
|
||||
|
@ -179,8 +178,8 @@ definitions in response to evaluating forms such as @racket[define].
|
|||
Each evaluation step, then, transforms the current set of definitions and
|
||||
program into a new set of definitions and program. Before a
|
||||
@racket[define] can be moved into the set of definitions, its
|
||||
second expression must be reduced to a @tech{value}.
|
||||
(The first expression is used without evaluation.)
|
||||
expression (i.e., its right-hand side) must be reduced to a @tech{value}.
|
||||
(The left-hand side is not evaluated.)
|
||||
|
||||
@prog-steps/no-obj[
|
||||
[{}
|
||||
|
@ -230,7 +229,7 @@ else. For example, a @tech{value} can refer to a particular vector that
|
|||
currently holds the value @racket[10] in its first slot. If an
|
||||
@tech{object} is modified via one @tech{value},
|
||||
then the modification is visible through
|
||||
all copies of the @tech{value} that reference the @tech{object}.
|
||||
all the @tech{values} that reference the @tech{object}.
|
||||
|
||||
In the evaluation model, a set of @tech{objects} must be carried along
|
||||
with each step in evaluation, just like the definition set. Operations
|
||||
|
@ -356,8 +355,8 @@ In the program state
|
|||
|
||||
evaluation cannot depend on @racket[<o2>], because it is not part of
|
||||
the program to evaluate, and it is not referenced by any definition
|
||||
that is accessible by the program. The object is said to be
|
||||
not @deftech{reachable}. The @tech{object} @racket[<o2>] may
|
||||
that is accessible by the program. The object is said to not
|
||||
be @deftech{reachable}. The @tech{object} @racket[<o2>] may
|
||||
therefore be removed from the program state by @deftech{garbage
|
||||
collection}.
|
||||
|
||||
|
@ -390,7 +389,7 @@ an algebra student simplifies @tt{f(7)} as follows:
|
|||
|
||||
@verbatim{ f(7) = 7 + 10 = 17}
|
||||
|
||||
The key step in this simplification is take the body of the defined
|
||||
The key step in this simplification is to take the body of the defined
|
||||
function @tt{f} and replace each @tt{x} with the actual
|
||||
@tech{value} @tt{7}.
|
||||
|
||||
|
@ -407,14 +406,17 @@ an @tech{object}, so evaluating @racket[(f 7)] starts with a
|
|||
(code:hilite (<p1> 7))]
|
||||
]
|
||||
|
||||
Unlike in algebra, however, the @tech{value} associated with an
|
||||
argument parameter variable (not to be confused with parameters;
|
||||
see @secref["parameter-model"]) can be changed in the body of a procedure by using
|
||||
Unlike in algebra, however, the @tech{value} associated with a procedure
|
||||
argument variable can be changed in the body of a procedure by using
|
||||
@racket[set!], as in the example @racket[(lambda (x) (begin (set! x 3)
|
||||
x))]. Since the @tech{value} associated with parameter variable @racket[x] can be
|
||||
changed, an argument value cannot be substituted for @racket[x] when
|
||||
x))]. Since the @tech{value} associated with argument variable @racket[x] can be
|
||||
changed, the value cannot be substituted for @racket[x] when
|
||||
the procedure is first applied.
|
||||
|
||||
@margin-note{We do not use the term ``parameter variable'' to refer to
|
||||
the parameter variable names declared with a function. This is to avoid
|
||||
confusion with Parameters (see @secref["parameter-model"]).}
|
||||
|
||||
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
|
||||
|
@ -445,7 +447,7 @@ accessed directly.
|
|||
|
||||
Generating a @tech{location} in this way means that @racket[set!]
|
||||
evaluates for @tech{local variables}, including argument
|
||||
parameter variables, in the same way as for
|
||||
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 @racket[set!]
|
||||
form is evaluated:
|
||||
|
@ -493,13 +495,13 @@ that replaces every instance of @racket[x] in @racket[_expr].
|
|||
|
||||
A @deftech{variable} is a placeholder for a @tech{value}, and
|
||||
expressions in an initial program refer to @tech{variables}. A
|
||||
@tech{top-level variable} is both a @tech{variable} and 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; thus, 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 an
|
||||
argument parameter variable, can correspond to different @tech{locations}
|
||||
through different applications.
|
||||
argument variable, can correspond to different @tech{locations}
|
||||
during different applications.
|
||||
|
||||
For example, in the program
|
||||
|
||||
|
@ -514,7 +516,7 @@ hold the value @racket[11].
|
|||
|
||||
The replacement of a @tech{variable} with a @tech{location} during
|
||||
evaluation implements Racket's @deftech{lexical scoping}. For example,
|
||||
when an argument parameter variable @racket[x] is replaced by
|
||||
when an argument variable @racket[x] is replaced by
|
||||
the @tech{location} @racket[xloc], it is replaced @italic{throughout} the
|
||||
body of the procedure, including any nested @racket[lambda]
|
||||
forms. As a result, future references to the @tech{variable} always
|
||||
|
@ -527,7 +529,7 @@ access the same @tech{location}.
|
|||
|
||||
Most definitions in Racket are in @deftech{modules}. In terms of evaluation,
|
||||
a module is essentially a prefix on a defined name, so that different
|
||||
modules can define the name. That is, a @deftech{module-level
|
||||
modules can define the same name. That is, a @deftech{module-level
|
||||
variable} is like a @tech{top-level variable} from the perspective of
|
||||
evaluation.
|
||||
|
||||
|
@ -535,7 +537,7 @@ One difference between a module and a top-level definition
|
|||
is that a module can be @deftech[#:key "declare"]{declared}
|
||||
without instantiating its module-level definitions.
|
||||
Evaluation of a @racket[require] @deftech{instantiates}
|
||||
(i.e., triggers the @deftech{instantiation} of) a declared
|
||||
(i.e., triggers the @deftech{instantiation} of) the declared
|
||||
module, which creates variables that correspond to its
|
||||
module-level definitions.
|
||||
|
||||
|
@ -548,46 +550,54 @@ For example, given the module declaration
|
|||
|
||||
the evaluation of @racket[(require 'm)] creates the variable @racket[x]
|
||||
and installs @racket[10] as its value. This @racket[x] is unrelated to
|
||||
any top-level definition of @racket[x].
|
||||
any top-level definition of @racket[x] (as if it were given a unique,
|
||||
module-specific prefix).
|
||||
|
||||
@;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
@;------------------------------------------------------------------------
|
||||
@subsection[#:tag "module-phase"]{Phases}
|
||||
|
||||
A module can be @tech{instantiate}d in multiple @deftech{phases}. A
|
||||
phase is an integer that, again, is effectively a prefix on the names
|
||||
of module-level definitions. A top-level @racket[require]
|
||||
The purpose of @deftech{phases} is to
|
||||
address the necessary separation of names defined at execution time versus
|
||||
names defined at expansion time. See Section @secref["phases"] in the Guide.
|
||||
|
||||
A module can be @tech{instantiate}d in multiple @tech{phases}. A
|
||||
phase is an integer that, like a module name, is effectively a prefix on the names
|
||||
of module-level definitions. Phase 0 is the execution-time phase.
|
||||
|
||||
A top-level @racket[require]
|
||||
@tech{instantiates} a module at @tech{phase} 0, if the module is not
|
||||
already @tech{instantiate}d at phase 0. A top-level
|
||||
@racket[(require (for-syntax ....))] @tech{instantiates} a module at
|
||||
@tech{phase} 1 (if it is not already @tech{instantiate}d at that
|
||||
level); @racket[for-syntax] also has a different binding
|
||||
phase); @racket[for-syntax] also has a different binding
|
||||
effect on further program parsing, as described in
|
||||
@secref["intro-binding"].
|
||||
|
||||
Within a module, some definitions are shifted by a phase already; the
|
||||
Within a module, some definitions are already shifted by a phase: the
|
||||
@racket[begin-for-syntax] form is similar to @racket[begin], but it
|
||||
shifts expressions and definitions by a relative @tech{phase} 1.
|
||||
shifts expressions and definitions by a relative @tech{phase} +1.
|
||||
Likewise, the @racket[define-for-syntax] form is similar to @racket[define],
|
||||
but shifts the definition by +1.
|
||||
Thus, if the module is @tech{instantiate}d at phase 1,
|
||||
the variables defined with @racket[begin-for-syntax] are created at phase 2,
|
||||
and so on. Moreover, this relative phase acts as another layer of
|
||||
prefixing, so that a @racket[define] of @racket[x] and a
|
||||
@racket[begin-for-syntax]-wrapped
|
||||
@racket[define] of @racket[x] can co-exist in a module
|
||||
prefixing, so that @racket[x] defined with @racket[define] and
|
||||
@racket[x] defined with @racket[define-for-syntax] can co-exist in a module
|
||||
without colliding. A @racket[begin-for-syntax] form can be nested
|
||||
within a @racket[begin-for-syntax] form, in which case definitions and
|
||||
expressions are in relative @tech{phase} 2, and so on. Higher phases are
|
||||
mainly related to program parsing, instead of normal evaluation.
|
||||
within a @racket[begin-for-syntax] form, in which case the inner definitions and
|
||||
expressions are in relative @tech{phase} +2, and so on. Higher phases are
|
||||
mainly related to program parsing instead of normal evaluation.
|
||||
|
||||
If a module @tech{instantiate}d at @tech{phase} @math{n}
|
||||
@racket[require]s another module, then the @racket[require]d module is
|
||||
first @tech{instantiate}d at phase @math{n}, and so on
|
||||
transitively. (Module @racket[require]s cannot form cycles.) If a
|
||||
module @tech{instantiate}d at phase @math{n} @racket[require]s
|
||||
@racket[for-syntax] another module, the other module becomes
|
||||
@deftech{available} at @tech{phase} @math{n+1}, and it may later be
|
||||
another module @racket[_M] @racket[for-syntax], then @racket[_M] becomes
|
||||
@deftech{available} at @tech{phase} @math{n+1}, and it later may be
|
||||
@tech{instantiate}d at @tech{phase} @math{n+1}. If a module that is
|
||||
@tech{available} at phase @math{n} for @math{n>0} @racket[require]s
|
||||
@racket[for-template] another module, the other module becomes
|
||||
@tech{available} at phase @math{n} (for @math{n>0}) @racket[require]s
|
||||
another module @racket[_M] @racket[for-template], then @racket[_M] becomes
|
||||
@tech{available} at @tech{phase} @math{n-1}, and so
|
||||
on. @tech{Instantiation}s of @tech{available} modules above
|
||||
@tech{phase} 0 are triggered on demand as described in
|
||||
|
@ -605,7 +615,7 @@ within modules. For example, @racket[define] within @racket[begin-for-syntax] cr
|
|||
@racket[make-base-namespace] and @racket[eval] provide access to
|
||||
top-level variables in higher @tech{phases}, while module
|
||||
@tech{instantiations} (triggered by @racket[require]) relative to such
|
||||
top-levels are in corresponding higher @tech{phase}s.
|
||||
top-levels are in correspondingly higher @tech{phase}s.
|
||||
|
||||
@;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
@subsection[#:tag "separate-compilation"]{The Separate Compilation Guarantee}
|
||||
|
@ -613,54 +623,55 @@ top-levels are in corresponding higher @tech{phase}s.
|
|||
When a module is compiled, its @tech{phase} 1 is instantiated. This
|
||||
can, in turn, trigger the transitive instantiation of many other
|
||||
modules at other phases, including phase 1. Racket provides a very
|
||||
strong guarantee about this instantiation called "The Separate
|
||||
Compilation Guarantee":
|
||||
strong guarantee about this instantiation called
|
||||
@index["separate compilation guarantee"]{``The Separate
|
||||
Compilation Guarantee''}:
|
||||
|
||||
"Any @tech{effects} of the instantiation of the module's phase 1 due
|
||||
to compilation on the Racket runtime system are @tech{discarded}."
|
||||
@nested[#:style 'inset]{Any @tech{effects} of the instantiation of the module's phase 1 due
|
||||
to compilation on the Racket runtime system are @tech{discarded}.}
|
||||
|
||||
The guarantee concerns @deftech{effects}. There are two different
|
||||
kinds of effects: internal and external.
|
||||
|
||||
Internal effects are exemplified by mutation. Mutation is the action
|
||||
of a function such as @racket[set-box!], which changes the value
|
||||
contained in the box. The modified box is not observable outside of
|
||||
Racket, so the effect is said to be "internal". By definition,
|
||||
internal effects is not detectable outside of the Racket program.
|
||||
contained in the box. The modified box is not observable outside
|
||||
Racket, so the effect is said to be ``internal.'' By definition,
|
||||
internal effects are not detectable outside the Racket program.
|
||||
|
||||
External effects are exemplified by input/output (or I/O). I/O is the
|
||||
External effects are exemplified by input/output (I/O). I/O is the
|
||||
action of a function such as @racket[tcp-connect], which communicates
|
||||
with the operating system to send network packets outside of the
|
||||
with the operating system to send network packets outside the
|
||||
machine running Racket. The transmission of these packets is
|
||||
observable outside of Racket, in particular by the receiver computer
|
||||
observable outside Racket, in particular by the receiving computer
|
||||
or any routers in between. External effects exist to be detectable
|
||||
outside of the Racket program and are often detectable using physical
|
||||
outside the Racket program and are often detectable using physical
|
||||
processes.
|
||||
|
||||
An effect is @deftech{discarded} when it is no longer detectable. For
|
||||
instance, a mutation of a box from @racket[3] to @racket[4] would be
|
||||
discarded if it ceases to be detectable that it was ever changed, and
|
||||
instance, the mutation of a box from @racket[3] to @racket[4] is
|
||||
discarded when it ceases to be detectable that it was ever changed and
|
||||
thus would still contain @racket[3]. Because external effects are
|
||||
intrinsically observable outside of Racket, they are irreversible and
|
||||
intrinsically observable outside Racket, they are irreversible and
|
||||
cannot be discarded.
|
||||
|
||||
Thus, The Separate Compilation Guarantee only concerns effects like
|
||||
mutation, because they are exclusively effects "on the Racket runtime
|
||||
system" and not "on the physical universe".
|
||||
mutation, because they are exclusively effects ``on the Racket runtime
|
||||
system'' and not ``on the physical universe.''
|
||||
|
||||
There are many things a Racket program can do that appear to be
|
||||
internal effects, but are actually external effects. For instance,
|
||||
internal effects but are actually external effects. For instance,
|
||||
@racket[bytes-set!] is typically an internal effect, except when the
|
||||
bytes were created by @racket[make-shared-bytes] which is allocated in
|
||||
space observable by other processes. Thus, effects which modify them
|
||||
are not discardable, so @racket[bytes-set!], in this case, is an
|
||||
bytes are created by @racket[make-shared-bytes], which allocates in
|
||||
space observable by other processes. Thus, effects which modify those
|
||||
bytes are not discardable, so @racket[bytes-set!], in this case, has an
|
||||
external effect.
|
||||
|
||||
The opposite is also true: some things which appear to be external are
|
||||
actually internal. For instance, if a Racket program starts multiple
|
||||
threads and uses mutation to communicate between them, that mutation
|
||||
is purely internal, because Racket's threads are defined entirely
|
||||
internally.
|
||||
internally (they are not related to operating system threads).
|
||||
|
||||
Furthermore, whenever a Racket program calls an @tech{unsafe}
|
||||
function, the Racket runtime system makes no promises about its
|
||||
|
@ -680,7 +691,8 @@ compilation of one module to have already compiled a different module.
|
|||
In particular, if module A is shared by the phase 1 portion of modules
|
||||
X and Y, then any internal effects while X is compiled are not visible
|
||||
during the compilation of Y, regardless of whether X and Y are
|
||||
compiled during the same execution of Racket's runtime system.
|
||||
compiled during the same execution of Racket's runtime system and
|
||||
regardless of the order of compilation.
|
||||
|
||||
The following set of modules demonstrate this guarantee. First, we
|
||||
define a module with the ability to observe effects via a
|
||||
|
@ -697,8 +709,7 @@ Next, we define two syntax transformers that use and mutate this box:
|
|||
@RACKETBLOCK[
|
||||
(module transformers racket/base
|
||||
(provide (all-defined-out))
|
||||
(require (for-syntax racket/base
|
||||
'box))
|
||||
(require (for-syntax racket/base 'box))
|
||||
(define-syntax (sett stx)
|
||||
(set-box! b 2)
|
||||
(syntax (void)))
|
||||
|
@ -716,7 +727,8 @@ Next, we define a module that uses these transformers:
|
|||
(define gott (gett)))
|
||||
]
|
||||
|
||||
Finally, we define a second module that uses these transformers:
|
||||
Finally, we define a second module that uses these
|
||||
transformers and the @racket[user] module:
|
||||
|
||||
@racketblock[
|
||||
(module test racket/base
|
||||
|
@ -733,10 +745,12 @@ Finally, we define a second module that uses these transformers:
|
|||
|
||||
This module displays:
|
||||
@itemize[
|
||||
@item{@litchar["2"], because the module @racket['user] expanded to @racket[2].}
|
||||
@item{@litchar["0"], because the effects of compiling @racket['user] were discarded.}
|
||||
@item{@litchar["2"], because the effect of @racket[(sett)] inside @racket['test] is not discarded.}
|
||||
@item{@litchar["0"], because the effects at phase 1 are irrelevant to the phase 0 use of @racket[b].}
|
||||
@item{@litchar["2"], because the @racket[(gett)] in module @racket[user] expanded to @racket[2].}
|
||||
@item{@litchar["0"], because the effects of compiling @racket[user] were discarded.}
|
||||
@item{@litchar["2"], because the effect of @racket[(sett)] inside @racket[test] has
|
||||
not yet been discarded.}
|
||||
@item{@litchar["0"], because the effects of @racket[sett] at
|
||||
phase 1 are irrelevant to the phase 0 use of @racket[b] in @racket[(unbox b)].}
|
||||
]
|
||||
|
||||
Furthermore, this display will never change, regardless of which order
|
||||
|
@ -748,9 +762,9 @@ In contrast, if these modules were changed to store the value of
|
|||
display @litchar["2"].
|
||||
|
||||
The Separate Compilation Guarantee is described in more detail
|
||||
in "Composable and Compilable Macros" @cite["Flatt02"], including
|
||||
informative examples. The paper "Advanced Macrology and the
|
||||
implementation of Typed Scheme" @cite["Culpepper07"] also contains an
|
||||
in the paper ``Composable and Compilable Macros'' @cite["Flatt02"], including
|
||||
informative examples. The paper ``Advanced Macrology and the
|
||||
implementation of Typed Scheme'' @cite["Culpepper07"] also contains an
|
||||
extended example of why it is important and how to design effectful
|
||||
syntactic extensions in its presence.
|
||||
|
||||
|
@ -797,7 +811,7 @@ they share a common module declaration.
|
|||
The intent of a @tech{cross-phase persistent} module is to support values that are
|
||||
recognizable after @tech{phase} crossings. For example, when a macro
|
||||
transformer running in phase 1 raises a syntax error as represented by
|
||||
a @racket[exn:fail:syntax] instance, the instance is recognizable by a
|
||||
an @racket[exn:fail:syntax] instance, the instance is recognizable by a
|
||||
phase-0 exception handler wrapping a call to @racket[eval] or
|
||||
@racket[expand] that triggered the syntax error, because the
|
||||
@racket[exn:fail:syntax] structure type is defined by a
|
||||
|
@ -812,7 +826,7 @@ literals (via @racket[quote-syntax]) or variable references (via
|
|||
the syntactic specification of a @tech{cross-phase persistent} module
|
||||
declaration.
|
||||
|
||||
A documented module should be assumed non-@tech{cross-phase persistent} unless it
|
||||
A documented module should be assumed non--@tech{cross-phase persistent} unless it
|
||||
is specified as @tech{cross-phase persistent} (such as
|
||||
@racketmodname[racket/kernel]).
|
||||
|
||||
|
@ -821,7 +835,7 @@ is specified as @tech{cross-phase persistent} (such as
|
|||
|
||||
@section-index["modules" "re-define"]
|
||||
|
||||
When a module is declared using a name for which a module is already
|
||||
When a module is declared using a name with which a module is already
|
||||
declared, the new declaration's definitions replace and extend the old
|
||||
declarations. If a variable in the old declaration has no counterpart
|
||||
in the new declaration, the old variable continues to exist, but its
|
||||
|
@ -858,9 +872,9 @@ can @racket[require] the submodule. In contrast, a submodule declared
|
|||
with @racket[module*] conceptually follows its enclosing module, so
|
||||
can @racket[require] from its enclosing module, but the enclosing
|
||||
module cannot @racket[require] the submodule. Unless a submodule
|
||||
imports from its enclosing module or vice-versa, then @tech{visits} or
|
||||
imports from its enclosing module or vice versa, then @tech{visits} or
|
||||
@tech{instantiations} of the two modules are independent, and their
|
||||
implementations may even be loaded from bytecode at different times.
|
||||
implementations may even be loaded from bytecode sources at different times.
|
||||
|
||||
A submodule declared with @racket[module] can import any preceding
|
||||
submodule declared with @racket[module]. A submodule declared with
|
||||
|
@ -882,16 +896,16 @@ Every continuation @racket[_C] can be partitioned into
|
|||
@deftech{continuation frames} @frame[1], @frame[2], ..., @frame["n"]
|
||||
such that @racket[_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 and remove frames to
|
||||
into smaller continuations. Evaluation steps add frames to and remove frames from
|
||||
the current continuation, typically one at a time.
|
||||
|
||||
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
|
||||
@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 given 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
|
||||
@tech{dynamic extent}. For example, marks can be used to record information
|
||||
for a ``stack trace'' to be presented when an exception is raised, or
|
||||
to implement dynamic scope.
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
|
@ -901,7 +915,7 @@ to implement dynamic scope.
|
|||
|
||||
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
|
||||
@tech{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
|
||||
|
@ -923,7 +937,7 @@ particular, when an exception handler is called, a continuation
|
|||
barrier prohibits the continuation of the handler from capturing the
|
||||
continuation past the exception point.
|
||||
|
||||
A @deftech{escape continuation} is essentially a derived concept. It
|
||||
An @deftech{escape continuation} is essentially a derived concept. It
|
||||
combines a prompt for escape purposes with a continuation for
|
||||
mark-gathering purposes. As the name implies, escape continuations are
|
||||
used only to abort to the point of capture.
|
||||
|
@ -936,11 +950,12 @@ used only to abort to the point of capture.
|
|||
Racket supports multiple @deftech{threads} of evaluation. Threads run
|
||||
concurrently, in the sense that one thread can preempt another without
|
||||
its cooperation, but threads currently all run on the same processor
|
||||
(i.e., the same underlying OS process and thread). See also
|
||||
(i.e., the same underlying operating system process and thread). See also
|
||||
@secref["futures"].
|
||||
|
||||
Threads are created explicitly by functions such as @racket[thread].
|
||||
In terms of the evaluation model, each step in evaluation actually consists of multiple concurrent
|
||||
In terms of the evaluation model, each step in evaluation
|
||||
actually deals with multiple concurrent
|
||||
expressions, up to one per thread, rather than a single expression. The expressions all
|
||||
share the same objects and top-level variables, so that they can
|
||||
communicate through shared state, and sequential consistency is
|
||||
|
@ -953,7 +968,7 @@ 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
|
||||
a value from that cell in 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
|
||||
|
@ -967,9 +982,9 @@ is created) as all other threads.
|
|||
|
||||
@deftech{Parameters} are essentially a derived concept in Racket; they
|
||||
are defined in terms of @tech{continuation marks} and @tech{thread
|
||||
cells}. However, parameters are also built in, in the sense that some
|
||||
cells}. However, parameters are also ``built in,'' due to the fact that some
|
||||
primitive procedures consult parameter values. For example, the
|
||||
default output stream for primitive output operations is determined by
|
||||
default output stream for primitive output operations is specified by
|
||||
a parameter.
|
||||
|
||||
A parameter is a setting that is both thread-specific and
|
||||
|
@ -980,10 +995,10 @@ 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 through a continuation mark (whose key is
|
||||
enclosing continuation frame via 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
|
||||
preserved thread cell, and the combination of the thread cell and the current
|
||||
thread yields the parameter's value. A @tech{parameter procedure} sets or
|
||||
accesses the relevant thread cell for its parameter.
|
||||
|
||||
Various operations, such as @racket[parameterize] or
|
||||
|
@ -997,15 +1012,15 @@ the current continuation's frame.
|
|||
|
||||
@deftech{Exceptions} are essentially a derived concept in Racket; they
|
||||
are defined in terms of continuations, prompts, and continuation
|
||||
marks. However, exceptions are also built in, in the sense that
|
||||
marks. However, exceptions are also ``built in,'' due to the fact that
|
||||
primitive forms and procedures may raise exceptions.
|
||||
|
||||
An @deftech{exception handler} to catch exceptions can be associated
|
||||
An @deftech{exception handler} to @deftech{catch} exceptions can be associated
|
||||
with a continuation frame though a @tech{continuation mark} (whose key
|
||||
is not directly accessible). When an exception is raised, the current
|
||||
continuation's marks determine a chain of @tech{exception handler}
|
||||
procedures that are consulted to handle the exception. A handler for
|
||||
uncaught exceptions is designated through a built-in @tech{parameter}.
|
||||
procedures that are consulted to handle the exception.
|
||||
A handler for uncaught exceptions is designated through a built-in @tech{parameter}.
|
||||
|
||||
One potential action of an @tech{exception handler} is to abort the
|
||||
current @tech{continuation} up to an enclosing @tech{prompt} with a
|
||||
|
@ -1048,8 +1063,8 @@ created with @racket[thread/suspend-to-kill] can have zero
|
|||
custodians. Extra custodians become associated with a thread through
|
||||
@racket[thread-resume] (see @secref["threadkill"]). When a thread
|
||||
has multiple custodians, it is not necessarily killed by a
|
||||
@racket[custodian-shutdown-all], but shut-down custodians are removed
|
||||
from the thread's managing set, and the thread is killed when its
|
||||
@racket[custodian-shutdown-all]. Instead, shut-down custodians are removed
|
||||
from the thread's managing custodian set, and the thread is killed when its
|
||||
managing set becomes empty.
|
||||
|
||||
The values managed by a custodian are only weakly held by the
|
||||
|
@ -1057,21 +1072,21 @@ custodian. As a result, a @techlink{will} can be executed for a value that
|
|||
is managed by a custodian. In addition, a custodian only weakly
|
||||
references its subordinate custodians; if a subordinate custodian is
|
||||
unreferenced but has its own subordinates, then the custodian may be
|
||||
collected, at which point its subordinates become immediately
|
||||
subordinate to the collected custodian's superordinate custodian.
|
||||
garbage collected, at which point its subordinates become immediately
|
||||
subordinate to the collected custodian's superordinate (owner) custodian.
|
||||
|
||||
In addition to the other entities managed by a custodian, a
|
||||
@deftech{custodian box} created with @racket[make-custodian-box]
|
||||
strongly holds onto a value placed in the box until the box's
|
||||
custodian is shut down. The custodian only weakly retains the box
|
||||
itself, however (so the box and its content can be collected if there
|
||||
are no other references to them).
|
||||
custodian is shut down. However, the custodian only weakly retains the box
|
||||
itself, so the box and its content can be collected if there
|
||||
are no other references to them.
|
||||
|
||||
When Racket is compiled with support for per-custodian memory
|
||||
accounting (see @racket[custodian-memory-accounting-available?]), the
|
||||
@racket[current-memory-use] procedure can report a custodian-specific
|
||||
result. This result determines how much memory is occupied by objects
|
||||
that are reachable from the custodian's managed values, especially its
|
||||
that are @tech{reachable} from the custodian's managed values, especially its
|
||||
threads, and including its sub-custodians' managed values. If an
|
||||
object is reachable from two custodians where neither is an ancestor
|
||||
of the other, an object is arbitrarily charged to one or the other,
|
||||
|
|
Loading…
Reference in New Issue
Block a user