744 lines
28 KiB
Racket
744 lines
28 KiB
Racket
#lang scribble/doc
|
|
@(require (except-in "mz.ss" link)
|
|
(for-label scheme/unit-exptime))
|
|
|
|
@(define-syntax defkeywords
|
|
(syntax-rules (*)
|
|
[(_ [* (form ...) as see])
|
|
(defform* [form ...]
|
|
"Allowed only in a " (scheme as) "; see " (scheme see) ".")]
|
|
[(_ [* (form ...) see-eg])
|
|
(defform* [form ...]
|
|
"Allowed only in certain forms; see, for example, " (scheme see-eg) ".")]
|
|
[(_ [form as see])
|
|
(defkeywords [* (form) as see])]
|
|
[(_ [form see-eg])
|
|
(defkeywords [* (form) see-eg])]
|
|
[(_ f ...)
|
|
(begin (defkeywords f) ...)]))
|
|
|
|
@title[#:tag "mzlib:unit" #:style 'toc]{Units}
|
|
|
|
@deftech{Units} organize a program into separately compilable and
|
|
reusable components. The imports and exports of a unit are grouped
|
|
into a @deftech{signature}, which can include ``static'' information
|
|
(such as macros) in addition to placeholders for run-time values.
|
|
Units with suitably matching signatures can be @deftech{linked}
|
|
together to form a larger unit, and a unit with no imports can be
|
|
@deftech{invoked} to execute its body.
|
|
|
|
@note-lib[scheme/unit #:use-sources (mzlib/unit)]{ The
|
|
@schememodname[scheme/unit] module name can be used as a language name
|
|
with @schemefont{#lang}; see @secref["single-unit"].}
|
|
|
|
@local-table-of-contents[]
|
|
|
|
@; ------------------------------------------------------------------------
|
|
|
|
@section[#:tag "creatingunits"]{Creating Units}
|
|
|
|
@defform/subs[
|
|
#:literals (import export prefix rename only except tag init-depend tag)
|
|
(unit
|
|
(import tagged-sig-spec ...)
|
|
(export tagged-sig-spec ...)
|
|
init-depends-decl
|
|
unit-body-expr-or-defn
|
|
...)
|
|
|
|
([tagged-sig-spec
|
|
sig-spec
|
|
(tag id sig-spec)]
|
|
|
|
[sig-spec
|
|
sig-id
|
|
(prefix id sig-spec)
|
|
(rename sig-spec (id id) ...)
|
|
(only sig-spec id ...)
|
|
(except sig-spec id ...)]
|
|
|
|
[init-depends-decl
|
|
code:blank
|
|
(init-depend tagged-sig-id ...)]
|
|
|
|
[tagged-sig-id
|
|
sig-id
|
|
(tag id sig-id)])]{
|
|
|
|
Produces a unit that encapsulates its
|
|
@scheme[unit-body-expr-or-defn]s. Expressions in the @scheme[unit]
|
|
body can refer to identifiers bound by the @scheme[sig-spec]s of the
|
|
@scheme[import] clause, and the body must include one definition for
|
|
each identifier of a @scheme[sig-spec] in the @scheme[export] clause.
|
|
An identifier that is exported cannot be @scheme[set!]ed in either the
|
|
defining unit or in importing units, although the implicit assignment
|
|
to initialize the variable may be visible as a mutation.
|
|
|
|
Each import or export @scheme[sig-spec] ultimately refers to a
|
|
@scheme[sig-id], which is an identifier that is bound to a signature
|
|
by @scheme[define-signature].
|
|
|
|
In a specific import or export position, the set of identifiers bound
|
|
or required by a particular @scheme[sig-id] can be adjusted in a few
|
|
ways:
|
|
|
|
@itemize{
|
|
|
|
@item{@scheme[(prefix id sig-spec)] as an import binds the same as
|
|
@scheme[sig-spec], except that each binding is prefixed with @scheme[id].
|
|
As an export, this form causes definitions using the @scheme[id]
|
|
prefix to satisfy the exports required by @scheme[sig-spec].}
|
|
|
|
@item{@scheme[(rename sig-spec (id id) ...)] as
|
|
an import binds the same as @scheme[sig-spec], except that the first @scheme[id]
|
|
is used for the binding instead of the second @scheme[id] (where
|
|
@scheme[sig-spec] by itself must imply a binding for the second @scheme[id]).
|
|
As an export, this form causes a definition for the first @scheme[id]
|
|
to satisfy the export named by the second @scheme[id] in @scheme[sig-spec].}
|
|
|
|
@item{@scheme[(only sig-spec id ...)] as
|
|
an import binds the same as @scheme[sig-spec], but restricted to just the
|
|
listed @scheme[id]s (where
|
|
@scheme[sig-spec] by itself must imply a binding for each @scheme[id]).
|
|
This form is not allowed for an export.}
|
|
|
|
@item{@scheme[(except sig-spec id ...)] as
|
|
an import binds the same as @scheme[sig-spec], but excluding all listed
|
|
@scheme[id]s (where
|
|
@scheme[sig-spec] by itself must imply a binding for each @scheme[id]).
|
|
This form is not allowed for an export.}
|
|
|
|
}
|
|
|
|
As suggested by the grammar, these adjustments to a signature can be
|
|
nested arbitrarily.
|
|
|
|
A unit's declared imports are matched with actual supplied imports by
|
|
signature. That is, the order in which imports are suppplied to a unit
|
|
when linking is irrelevant; all that matters is the signature
|
|
implemented by each supplied import. One actual import must be
|
|
provided for each declared import. Similarly, when a unit implements
|
|
multiple signatures, the order of the export signatures does not
|
|
matter.
|
|
|
|
To support multiple imports or exports for the same signature, an
|
|
import or export can be tagged using the form @scheme[(tag
|
|
id sig-spec)]. When an import declaration of a unit is
|
|
tagged, then one actual import must be given the same tag (with the
|
|
same signature) when the unit is linked. Similarly, when an export
|
|
declaration is tagged for a unit, then references to that particular
|
|
export must explicitly use the tag.
|
|
|
|
A unit is prohibited syntactically from importing two signatures that
|
|
are not distinct, unless they have different tags; two signatures are
|
|
@defterm{distinct} only if when they share no ancestor through
|
|
@scheme[extends]. The same syntactic constraint applies to exported
|
|
signatures. In addition, a unit is prohibited syntactically from
|
|
importing the same identifier twice (after renaming and other
|
|
transformations on a @scheme[sig-spec]), exporting the same identifier
|
|
twice (again, after renaming), or exporting an identifier that is
|
|
imported.
|
|
|
|
When units are linked, the bodies of the linked units are
|
|
executed in an order that is specified at the linking site. An
|
|
optional @scheme[(init-depend tagged-sig-id ...)]
|
|
declaration constrains the allowed orders of linking by specifying
|
|
that the current unit must be initialized after the unit that supplies
|
|
the corresponding import. Each @scheme[tagged-sig-id] in an
|
|
@scheme[init-depend] declaration must have a corresponding import in the
|
|
@scheme[import] clause.}
|
|
|
|
@defform/subs[
|
|
#:literals (define-syntaxes define-values open extends)
|
|
(define-signature id extension-decl
|
|
(sig-elem ...))
|
|
|
|
([extension-decl
|
|
code:blank
|
|
(code:line extends sig-id)]
|
|
|
|
[sig-elem
|
|
id
|
|
(define-syntaxes (id ...) expr)
|
|
(define-values (value-id ...) expr)
|
|
(open sig-spec)
|
|
(sig-form-id . datum)])]{
|
|
|
|
Binds an identifier to a signature that specifies a group
|
|
of bindings for import or export:
|
|
|
|
@itemize{
|
|
|
|
@item{Each @scheme[id] in a signature declaration means that a unit
|
|
implementing the signature must supply a variable definition for the
|
|
@scheme[id]. That is, @scheme[id] is available for use in units
|
|
importing the signature, and @scheme[id] must be defined by units
|
|
exporting the signature.}
|
|
|
|
@item{Each @scheme[define-syntaxes] form in a signature declaration
|
|
introduces a macro to that is available for use in any unit that
|
|
imports the signature. Free variables in the definition's
|
|
@scheme[expr] refer to other identifiers in the signature first, or
|
|
the context of the @scheme[define-signature] form if the signature
|
|
does not include the identifier.}
|
|
|
|
@item{Each @scheme[define-values] form in a signature declaration
|
|
introduces code that effectively prefixes every unit that imports the
|
|
signature. Free variables in the definition's @scheme[expr] are
|
|
treated the same as for @scheme[define-syntaxes].}
|
|
|
|
@item{Each @scheme[(open sig-spec)] adds to the signature everything
|
|
specified by @scheme[sig-spec].}
|
|
|
|
@item{Each @scheme[(sig-form-id . datum)] extends the signature in a
|
|
way that is defined by @scheme[sig-form-id], which must be bound by
|
|
@scheme[define-signature-form]. One such binding is for
|
|
@scheme[struct].}
|
|
|
|
}
|
|
|
|
When a @scheme[define-signature] form includes a @scheme[extends]
|
|
clause, then the define signature automatically includes everything in
|
|
the extended signature. Furthermore, any implementation of the new
|
|
signature can be used as an implementation of the extended signature.}
|
|
|
|
@defkeywords[[(open sig-spec) _sig-elem define-signature]
|
|
[(only sig-spec id ...) _sig-spec unit]
|
|
[(except sig-spec id ...) _sig-spec unit]
|
|
[(rename sig-spec (id id) ...) _sig-spec unit]
|
|
[(prefix id sig-spec) _sig-spec unit]
|
|
[(import tagged-sig-spec ...) unit]
|
|
[(export tagged-sig-spec ...) unit]
|
|
[(link linkage-decl ...) compound-unit]
|
|
[* [(tag id sig-spec)
|
|
(tag id sig-id)] unit]
|
|
[(init-depend tagged-sig-id ...) init-depend-decl unit]]
|
|
|
|
@defidform[extends]{
|
|
|
|
This form is allowed only within @scheme[define-signature].}
|
|
|
|
@; ------------------------------------------------------------------------
|
|
|
|
@section[#:tag "invokingunits"]{Invoking Units}
|
|
|
|
@defform*[#:literals (import)
|
|
[(invoke-unit unit-expr)
|
|
(invoke-unit unit-expr (import tagged-sig-spec ...))]]{
|
|
|
|
Invokes the unit produced by @scheme[unit-expr]. For each of the
|
|
unit's imports, the @scheme[invoke-unit] expression must contain a
|
|
@scheme[tagged-sig-spec] in the @scheme[import] clause; see
|
|
@scheme[unit] for the grammar of @scheme[tagged-sig-spec]. If the unit
|
|
has no imports, the @scheme[import] clause can be omitted.
|
|
|
|
When no @scheme[tagged-sig-spec]s are provided, @scheme[unit-expr]
|
|
must produce a unit that expect no imports. To invoke the unit, all
|
|
bindings are first initialized to the @|undefined-const| value. Next,
|
|
the unit's body definitions and expressions are evaluated in order; in
|
|
the case of a definition, evaluation sets the value of the
|
|
corresponding variable(s). Finally, the result of the last expression
|
|
in the unit is the result of the @scheme[invoke-unit] expression.
|
|
|
|
Each supplied @scheme[tagged-sig-spec] takes bindings from the
|
|
surrounding context and turns them into imports for the invoked unit.
|
|
The unit need not declare an imports for evey provided
|
|
@scheme[tagged-sig-spec], but one @scheme[tagged-sig-spec] must be
|
|
provided for each declared import of the unit. For each variable
|
|
identifier in each provided @scheme[tagged-sig-spec], the value of the
|
|
identifier's binding in the surrounding context is used for the
|
|
corresponding import in the invoked unit.}
|
|
|
|
@defform[
|
|
#:literals (import export)
|
|
(define-values/invoke-unit unit-expr
|
|
(import tagged-sig-spec ...)
|
|
(export tagged-sig-spec ...))]{
|
|
|
|
Like @scheme[invoke-unit], but the values of the unit's exports are
|
|
copied to new bindings.
|
|
|
|
The unit produced by @scheme[unit-expr] is linked and invoked as for
|
|
@scheme[invoke-unit]. In addition, the @scheme[export] clause is
|
|
treated as a kind of import into the local definition context. That
|
|
is, for every binding that would be available in a unit that used the
|
|
@scheme[export] clauses's @scheme[tagged-sig-spec] as an import, a
|
|
definition is generated for the context of the
|
|
@scheme[define-values/invoke-unit] form.}
|
|
|
|
@; ------------------------------------------------------------------------
|
|
|
|
@section[#:tag "compoundunits"]{Linking Units and Creating Compound Units}
|
|
|
|
@defform/subs[
|
|
#:literals (: import export link tag)
|
|
(compound-unit
|
|
(import link-binding ...)
|
|
(export tagged-link-id ...)
|
|
(link linkage-decl ...))
|
|
|
|
([link-binding
|
|
(link-id : tagged-sig-id)]
|
|
|
|
[tagged-link-id
|
|
(tag id link-id)
|
|
link-id]
|
|
|
|
[linkage-decl
|
|
((link-binding ...) unit-expr tagged-link-id)])]{
|
|
|
|
Links several units into one new compound unit without immediately
|
|
invoking any of the linked units. The @scheme[unit-expr]s in the
|
|
@scheme[link] clause determine the units to be linked in creating the
|
|
compound unit. The @scheme[unit-expr]s are evaluated when the
|
|
@scheme[compound-unit] form is evaluated.
|
|
|
|
The @scheme[import] clause determines the imports of the compound
|
|
unit. Outside the compound unit, these imports behave as for a plain
|
|
unit; inside the compound unit, they are propagated to some of the
|
|
linked units. The @scheme[export] clause determines the exports of the
|
|
compound unit. Again, outside the compound unit, these exports are
|
|
trested the same as for a plain unit; inside the compound unit, they
|
|
are drawn from the exports of the linked units. Finally, the left-hand
|
|
and right-hand parts of each declaration in the @scheme[link] clause
|
|
specify how the compound unit's imports and exports are propagated to
|
|
the linked units.
|
|
|
|
Individual elements of an imported or exported signature are not
|
|
available within the compound unit. Instead, imports and exports are
|
|
connected at the level of whole signatures. Each specific import or
|
|
export (i.e., an instance of some signature, possibly tagged) is given
|
|
a @scheme[link-id] name. Specifically, a @scheme[link-id] is bound by
|
|
the @scheme[import] clause or the left-hand part of an declaration in
|
|
the @scheme[link] clause. A bound @scheme[link-id] is referenced in
|
|
the right-hand part of a declaration in the @scheme[link] clause or by
|
|
the @scheme[export] clause.
|
|
|
|
The left-hand side of a @scheme[link] declaration gives names to each
|
|
expected export of the unit produced by the corresponding
|
|
@scheme[unit-expr]. The actual unit may export additional signatures,
|
|
and it may export an extension of a specific signature instead of just
|
|
the specified one. If the unit does not export one of the specified
|
|
signatures (with the specified tag, if any), the
|
|
@exnraise[exn:fail:contract] when the @scheme[compound-unit] form is
|
|
evaluated.
|
|
|
|
The right-hand side of a @scheme[link] declaration specifies the
|
|
imports to be supplied to the unit produced by the corresponding
|
|
@scheme[unit-expr]. The actual unit may import fewer signatures, and
|
|
it may import a signature that is extended by the specified one. If
|
|
the unit imports a signature (with a particular tag) that is not
|
|
included in the supplied imports, the @exnraise[exn:fail:contract]
|
|
when the @scheme[compound-unit] form is evaluated. Each
|
|
@scheme[link-id] supplied as an import must be bound either in the
|
|
@scheme[import] clause or in some declaration within the @scheme[link]
|
|
clause.
|
|
|
|
The order of declarations in the @scheme[link] clause determines the
|
|
order of invocation of the linked units. When the compound unit is
|
|
invoked, the unit produced by the first @scheme[unit-expr] is invoked
|
|
first, then the second, and so on. If the order specified in the
|
|
@scheme[link] clause is inconsistent with @scheme[init-depend]
|
|
declarations of the actual units, then the
|
|
@exnraise[exn:fail:contract] when the @scheme[compound-unit] form is
|
|
evaluated.}
|
|
|
|
@; ------------------------------------------------------------------------
|
|
|
|
@section[#:tag "linkinference"]{Inferred Linking}
|
|
|
|
@defform[
|
|
#:literals (import export)
|
|
(define-unit unit-id
|
|
(import tagged-sig-spec ...)
|
|
(export tagged-sig-spec ...)
|
|
init-depends-decl
|
|
unit-body-expr-or-defn
|
|
...)
|
|
]{
|
|
|
|
Binds @scheme[unit-id] to both a unit and static information about the
|
|
unit.
|
|
|
|
Evaluating a reference to an @scheme[unit-id] bound by
|
|
@scheme[define-unit] produces a unit, just like evaluating an
|
|
@scheme[id] bound by @scheme[(define id (unit ...))]. In addition,
|
|
however, @scheme[unit-id] can be used in @scheme[compound-unit/infer].
|
|
See @scheme[unit] for information on @scheme[tagged-sig-spec],
|
|
@scheme[init-depends-decl], and @scheme[unit-body-expr-or-defn].}
|
|
|
|
@defform/subs[
|
|
#:literals (import export :)
|
|
(compound-unit/infer
|
|
(import tagged-infer-link-import ...)
|
|
(export tagged-infer-link-export ...)
|
|
(link infer-linkage-decl ...))
|
|
|
|
([tagged-infer-link-import
|
|
tagged-sig-id
|
|
(link-id : tagged-sig-id)]
|
|
|
|
[tagged-infer-link-export
|
|
(tag id infer-link-export)
|
|
infer-link-export]
|
|
|
|
[infer-link-export
|
|
link-id
|
|
sig-id]
|
|
|
|
[infer-linkage-decl
|
|
((link-binding ...) unit-id
|
|
tagged-link-id)
|
|
unit-id])]{
|
|
|
|
Like @scheme[compound-unit]. Syntactically, the difference between
|
|
@scheme[compound-unit] and @scheme[compound-unit/infer] is that the
|
|
@scheme[unit-expr] for a linked unit is replaced with a
|
|
@scheme[unit-id], where a @scheme[unit-id] is bound by
|
|
@scheme[define-unit] (or one of the other unit-binding forms that we
|
|
introduce later in this section). Furthermore, an import can name just
|
|
a @scheme[sig-id] without locally binding a @scheme[link-id], and an
|
|
export can be based on a @scheme[sig-id] instead of a
|
|
@scheme[link-id], and a declaration in the @scheme[link] clause can be
|
|
simply a @scheme[unit-id] with no specified exports or imports.
|
|
|
|
The @scheme[compound-unit/infer] form expands to
|
|
@scheme[compound-unit] by adding @scheme[sig-ids] as needed to
|
|
the @scheme[import] clause, by replacing @scheme[sig-id]s in the
|
|
@scheme[export] clause by @scheme[link-id]s, and by completing
|
|
the declarations of the @scheme[link] clause. This completion is based
|
|
on static information associated with each
|
|
@scheme[unit-id]. Links and exports can be inferred when all
|
|
signatures exported by the linked units are distinct from each other
|
|
and from all imported signatures, and when all imported signatures are
|
|
distinct. Two signatures are @defterm{distinct} only if when they
|
|
share no ancestor through @scheme[extends].
|
|
|
|
The long form of a @scheme[link] declaration can be used to resolve
|
|
ambiguity by giving names to some of a unit's exports and supplying
|
|
specific bindings for some of a unit's imports. The long form need not
|
|
name all of a unit's exports or supply all of a unit's imports if the
|
|
remaining parts can be inferred.
|
|
|
|
Like @scheme[compound-unit], the @scheme[compound-unit/infer] form
|
|
produces a (compound) unit without statically binding information
|
|
about the result unit's imports and exports. That is,
|
|
@scheme[compound-unit/infer] consumes static information, but it does
|
|
not generate it. Two additional forms,
|
|
@scheme[define-compound-unit] and
|
|
@scheme[define-compound-unit/infer], generate static information
|
|
(where the former does not consume static information).}
|
|
|
|
@defform[
|
|
#:literals (import export link)
|
|
(define-compound-unit id
|
|
(import link-binding ...)
|
|
(export tagged-link-id ...)
|
|
(link linkage-decl ...))
|
|
]{
|
|
|
|
Like @scheme[compound-unit], but binds static information about the
|
|
compound unit like @scheme[define-unit].}
|
|
|
|
|
|
@defform[
|
|
#:literals (import export link)
|
|
(define-compound-unit/infer id
|
|
(import link-binding ...)
|
|
(export tagged-infer-link-export ...)
|
|
(link infer-linkage-decl ...))
|
|
]{
|
|
|
|
Like @scheme[compound-unit/infer], but binds static information about
|
|
the compound unit like @scheme[define-unit].}
|
|
|
|
@defform[
|
|
#:literals (import export)
|
|
(define-unit-binding unit-id
|
|
unit-expr
|
|
(import tagged-sig-spec ...+)
|
|
(export tagged-sig-spec ...+)
|
|
init-depends-decl)
|
|
]{
|
|
|
|
Like @scheme[define-unit], but the unit implementation is determined
|
|
from an existing unit produced by @scheme[unit-expr]. The imports and
|
|
exports of the unit produced by @scheme[unit-expr] must be consistent
|
|
with the declared imports and exports, otherwise the
|
|
@exnraise[exn:fail:contract] when the @scheme[define-unit-binding]
|
|
form is evaluated.}
|
|
|
|
@defform[(invoke-unit/infer unit-id)]{
|
|
|
|
Like @scheme[invoke-unit], but uses static information associated with
|
|
@scheme[unit-id] to infer which imports must be assembled from the
|
|
current context.}
|
|
|
|
@defform[(define-values/invoke-unit/infer unit-id)]{
|
|
|
|
Like @scheme[define-values/invoke-unit], but uses static information
|
|
associated with @scheme[unit-id] to infer which imports must be
|
|
assembled from the current context and what exports should be bound
|
|
by the definition.}
|
|
|
|
@; ------------------------------------------------------------------------
|
|
|
|
@section{Generating A Unit from Context}
|
|
|
|
@defform[
|
|
(unit-from-context tagged-sig-spec)
|
|
]{
|
|
|
|
Creates a unit that implements an interface using bindings in the
|
|
enclosing environment. The generated unit is essentially the same as
|
|
|
|
@schemeblock[
|
|
(unit
|
|
(import)
|
|
(export tagged-sig-spec)
|
|
(define id expr) ...)
|
|
]
|
|
|
|
for each @scheme[id] that must be defined to satisfy the exports, and
|
|
each corresponding @scheme[expr] produces the value of @scheme[id] in
|
|
the environment of the @scheme[unit-from-context] expression. (The unit
|
|
cannot be written as above, however, since each @scheme[id] definition
|
|
within the unit shadows the binding outside the @scheme[unit] form.)
|
|
|
|
See @scheme[unit] for the grammar of @scheme[tagged-sig-spec].}
|
|
|
|
@defform[
|
|
(define-unit-from-context id tagged-sig-spec)
|
|
]{
|
|
|
|
Like @scheme[unit-from-context], in that a unit is constructed from
|
|
the enclosing environment, and like @scheme[define-unit], in that
|
|
@scheme[id] is bound to static information to be used later with inference.}
|
|
|
|
@; ------------------------------------------------------------------------
|
|
|
|
@section{Structural Matching}
|
|
|
|
@defform[
|
|
#:literals (import export)
|
|
(unit/new-import-export
|
|
(import tagged-sig-spec ...)
|
|
(export tagged-sig-spec ...)
|
|
init-depends-decl
|
|
((tagged-sig-spec ...) unit-expr tagged-sig-spec))
|
|
]{
|
|
|
|
Similar to @scheme[unit], except the body of the unit is determined by
|
|
an existing unit produced by @scheme[unit-expr]. The result is a unit
|
|
that whose implementation is @scheme[unit-expr], but whose imports,
|
|
exports, and initialization dependencies are as in the
|
|
@scheme[unit/new-import-export] form (instead of as in the unit
|
|
produced by @scheme[unit-expr]).
|
|
|
|
The final clause of the @scheme[unit/new-import-export] form
|
|
determines the connection between the old and new imports and exports.
|
|
The connection is similar to the way that @scheme[compound-unit]
|
|
propagates imports and exports; the difference is that the connection
|
|
between @scheme[import] and the right-hand side of the link clause is
|
|
based on the names of elements in signatures, rather than the names of
|
|
the signatures. That is, a @scheme[tagged-sig-spec] on the right-hand
|
|
side of the link clause need not apppear as a @scheme[tagged-sig-spec]
|
|
in the @scheme[import] clause, but each of the bindings implied by the
|
|
linking @scheme[tagged-sig-spec] must be implied by some
|
|
@scheme[tagged-sig-spec] in the @scheme[import] clause. Similarly,
|
|
each of the bindings implied by an @scheme[export]
|
|
@scheme[tagged-sig-spec] must be implied by some left-hand-side
|
|
@scheme[tagged-sig-spec] in the linking clause.}
|
|
|
|
@defform[
|
|
#:literals (import export)
|
|
(define-unit/new-import-export unit-id
|
|
(import tagged-sig-spec ...)
|
|
(export tagged-sig-spec ...)
|
|
init-depends-decl
|
|
((tagged-sig-spec ...) unit-expr tagged-sig-spec))
|
|
]{
|
|
|
|
Like @scheme[unit/new-import-export], but binds static information to
|
|
@scheme[unit-id] like @scheme[define-unit].}
|
|
|
|
@; ------------------------------------------------------------------------
|
|
|
|
@section[#:tag "define-sig-form"]{Extending the Syntax of Signatures}
|
|
|
|
@defform*[
|
|
[(define-signature-form sig-form-id expr)
|
|
(define-signature-form (sig-form-id id) body ...+)]
|
|
]
|
|
|
|
Binds @scheme[sig-form-id] for use within a @scheme[define-signature]
|
|
form.
|
|
|
|
In the first form, the result of @scheme[expr] must be a transformer
|
|
procedure. In the second form, @scheme[sig-form-id] is bound to a
|
|
transformer procedure whose argument is @scheme[id] and whose body is
|
|
the @scheme[body]s. The result of the transformer must be a list of
|
|
syntax objects, which are substituted for a use of
|
|
@scheme[sig-form-id] in a @scheme[define-signature] expansion. (The
|
|
result is a list so that the transformer can produce multiple
|
|
declarations; @scheme[define-signature] has no splicing @scheme[begin]
|
|
form.)}
|
|
|
|
@defform/subs[
|
|
(struct id (field ...) option ...)
|
|
|
|
([field id
|
|
[id #:mutable]]
|
|
[option #:mutable
|
|
#:omit-constructor
|
|
#:omit-define-syntaxes
|
|
#:omit-define-values])]{
|
|
|
|
For use with @scheme[define-signature]. The expansion of a
|
|
@scheme[struct] signature form includes all of the identifiers that
|
|
would be bound by @scheme[(define-struct id (field ...) option ...)],
|
|
where the extra option @scheme[#:omit-constructor] omits the
|
|
@schemeidfont{make-}@scheme[id] identifier.}
|
|
|
|
@; ------------------------------------------------------------------------
|
|
|
|
@section{Unit Utilities}
|
|
|
|
@defproc[(unit? [v any/c]) boolean?]{
|
|
|
|
Returns @scheme[#t] if @scheme[v] is a unit, @scheme[#f] otherwise.}
|
|
|
|
|
|
@defform[(provide-signature-elements sig-spec ...)]{
|
|
|
|
Expands to a @scheme[provide] of all identifiers implied by the
|
|
@scheme[sig-spec]s. See @scheme[unit] for the grammar of
|
|
@scheme[sig-spec].}
|
|
|
|
@; ------------------------------------------------------------------------
|
|
|
|
@section[#:tag "single-unit"]{Single-Unit Modules}
|
|
|
|
When @schememodname[scheme/unit] is used as a language name with
|
|
@schemefont{#lang}, the module body is treated as a unit body. The
|
|
body must match the following @scheme[_module-body] grammar:
|
|
|
|
@schemegrammar*[
|
|
#:literals (import export require begin)
|
|
[module-body (code:line
|
|
require-decl ...
|
|
(import tagged-sig-expr ...)
|
|
(export tagged-sig-expr ...)
|
|
init-depends-decl
|
|
unit-body-expr-or-defn
|
|
...)]
|
|
[require-decl (require require-spec ...)
|
|
(begin require-decl ...)
|
|
derived-require-form]]
|
|
|
|
After any number of @scheme[_require-decl]s, the content of the module
|
|
is the same as a @scheme[unit] body.
|
|
|
|
The resulting unit is exported as @scheme[_base]@schemeidfont["@"],
|
|
where @scheme[_base] is derived from the enclosing module's name
|
|
(i.e., its symbolic name, or its path without the directory and file
|
|
suffix). If the module name ends in @schemeidfont{-unit}, then
|
|
@scheme[_base] corresponds to the module name before
|
|
@schemeidfont{-unit}. Otherwise, the module name serves as
|
|
@scheme[_base].
|
|
|
|
@; ------------------------------------------------------------------------
|
|
|
|
@section{Single-Signature Modules}
|
|
|
|
@defmodulelang[scheme/signature]{The @schememodname[scheme/signature]
|
|
language treats a module body as a unit signature.}
|
|
|
|
The body must match the following @scheme[_module-body] grammar:
|
|
|
|
@schemegrammar*[
|
|
#:literals (require)
|
|
[module-body (code:line (require require-spec ...) ... sig-spec ...)]
|
|
]
|
|
|
|
See @secref["creatingunits"] for the grammar of @scheme[_sig-spec].
|
|
Unlike the body of a @schememodname[scheme/unit] module, a
|
|
@scheme[require] in a @schememodname[scheme/signature] module must be
|
|
a literal use of @scheme[require].
|
|
|
|
|
|
The resulting signature is exported as
|
|
@scheme[_base]@schemeidfont["^"], where @scheme[_base] is derived from
|
|
the enclosing module's name (i.e., its symbolic name, or its path
|
|
without the directory and file suffix). If the module name ends in
|
|
@schemeidfont{-sig}, then @scheme[_base] corresponds to the module
|
|
name before @schemeidfont{-sig}. Otherwise, the module name serves as
|
|
@scheme[_base].
|
|
|
|
@; ----------------------------------------------------------------------
|
|
|
|
@section{Transformer Helpers}
|
|
|
|
@defmodule[scheme/unit-exptime #:use-sources (mzlib/unit-exptime)]
|
|
|
|
The @schememodname[scheme/unit-exptime] library provides procedures
|
|
that are intended for use by macro transformers. In particular, the
|
|
library is typically imported using @scheme[for-syntax] into a module
|
|
that defines macro with @scheme[define-syntax].
|
|
|
|
@defproc[(unit-static-signatures [unit-identifier identifier?]
|
|
[err-syntax syntax?])
|
|
(values (list/c (cons/c (or/c symbol? false/c)
|
|
identifier?))
|
|
(list/c (cons/c (or/c symbol? false/c)
|
|
identifier?)))]{
|
|
|
|
If @scheme[unit-identifier] is bound to static unit information via
|
|
@scheme[define-unit] (or other such forms), the result is two
|
|
values. The first value is for the unit's imports, and the second is
|
|
for the unit's exports. Each result value is a list, where each list
|
|
element pairs a symbol or @scheme[#f] with an identifier. The symbol
|
|
or @scheme[#f] indicates the import's or export's tag (where
|
|
@scheme[#f] indicates no tag), and the identifier indicates the
|
|
binding of the corresponding signature.
|
|
|
|
If @scheme[unit-identifier] is not bound to static unit information,
|
|
then the @exnraise[exn:fail:syntax]. In that case, the given
|
|
@scheme[err-syntax] argument is used as the source of the error, where
|
|
@scheme[unit-identifer] is used as the detail source location.}
|
|
|
|
|
|
@defproc[(signature-members [sig-identifier identifier?]
|
|
[err-syntax syntax?])
|
|
(values (or/c identifier? false/c)
|
|
(listof identifier?)
|
|
(listof identifier?)
|
|
(listof identifier?))]{
|
|
|
|
If @scheme[sig-identifier] is bound to static unit information via
|
|
@scheme[define-signature] (or other such forms), the result is four
|
|
values:
|
|
|
|
@itemize{
|
|
|
|
@item{an identifier or @scheme[#f] indicating the signature (of any)
|
|
that is extended by the @scheme[sig-identifier] binding;}
|
|
|
|
@item{a list of identifiers representing the variables
|
|
supplied/required by the signature;}
|
|
|
|
@item{a list of identifiers for variable definitions in the
|
|
signature (i.e., variable bindings that are provided on
|
|
import, but not defined by units that implement the
|
|
signature); and}
|
|
|
|
@item{a list of identifiers with syntax definitions in the signature.}
|
|
|
|
}
|
|
|
|
If @scheme[sig-identifier] is not bound to a signature, then the
|
|
@exnraise[exn:fail:syntax]. In that case, the given
|
|
@scheme[err-syntax] argument is used as the source of the error, where
|
|
@scheme[sig-identifier] is used as the detail source location.}
|
|
|