From 08c04d2579c36bca447011c4b6b898cfcacaa7f1 Mon Sep 17 00:00:00 2001 From: Matthew Flatt Date: Fri, 27 Jul 2007 17:23:14 +0000 Subject: [PATCH] units chapter in reference svn: r6976 --- collects/scribble/manual.ss | 1 + collects/scribblings/reference/class.scrbl | 4 +- .../scribblings/reference/reference.scrbl | 1 + collects/scribblings/reference/units.scrbl | 628 ++++++++++++++++++ 4 files changed, 632 insertions(+), 2 deletions(-) create mode 100644 collects/scribblings/reference/units.scrbl diff --git a/collects/scribble/manual.ss b/collects/scribble/manual.ss index 438f96c4db..aa6cbcd929 100644 --- a/collects/scribble/manual.ss +++ b/collects/scribble/manual.ss @@ -303,6 +303,7 @@ [(_ [spec ...] desc ...) #'(defform*/subs [spec ...] () desc ...)])) (define-syntax (defform stx) (syntax-case stx () + [(_ #:literals (lit ...) spec desc ...) #'(defform*/subs #:literals (lit ...) [spec] () desc ...)] [(_ spec desc ...) #'(defform*/subs [spec] () desc ...)])) (define-syntax (defform/subs stx) (syntax-case stx () diff --git a/collects/scribblings/reference/class.scrbl b/collects/scribblings/reference/class.scrbl index 6527a30305..fbb7d237f1 100644 --- a/collects/scribblings/reference/class.scrbl +++ b/collects/scribblings/reference/class.scrbl @@ -71,6 +71,8 @@ @title[#:tag "mzlib:class" #:style 'toc]{Classes and Objects} +@local-table-of-contents[] + A @deftech{class} specifies @itemize{ @@ -143,8 +145,6 @@ Classes, objects, and interfaces are all values. However, a class or interface is not an object (i.e., there are no ``meta-classes'' or ``meta-interfaces''). -@local-table-of-contents[] - @; ------------------------------------------------------------------------ @section[#:tag "mz:createinterface"]{Creating Interfaces} diff --git a/collects/scribblings/reference/reference.scrbl b/collects/scribblings/reference/reference.scrbl index a1272ab6cd..b888b14d67 100644 --- a/collects/scribblings/reference/reference.scrbl +++ b/collects/scribblings/reference/reference.scrbl @@ -20,6 +20,7 @@ language. @include-section["data.scrbl"] @include-section["struct.scrbl"] @include-section["class.scrbl"] +@include-section["units.scrbl"] @include-section["control.scrbl"] @include-section["concurrency.scrbl"] @include-section["macros.scrbl"] diff --git a/collects/scribblings/reference/units.scrbl b/collects/scribblings/reference/units.scrbl new file mode 100644 index 0000000000..633659e307 --- /dev/null +++ b/collects/scribblings/reference/units.scrbl @@ -0,0 +1,628 @@ +#reader(lib "docreader.ss" "scribble") +@require[(all-except "mz.ss" link)] +@require[(lib "unit.ss")] +@require-for-syntax[mzscheme] + +@begin[ +(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} + +@local-table-of-contents[] + +@deftech{Units} are used to organize a program into separately +compilable and reusable components. A unit resembles a procedure in +that both are first-class values that are used for abstraction. While +procedures abstract over values in expressions, units abstract over +names in collections of definitions. Just as a procedure is invoked to +evaluate its expressions given actual arguments for its formal +parameters, a unit is invoked to evaluate its definitions given actual +references for its imported variables. Unlike a procedure, however, a +unit's imported variables can be partially linked with the exported +variables of another unit {\em prior to invocation}. Linking merges +multiple units together into a single compound unit. The compound unit +itself imports variables that will be propagated to unresolved +imported variables in the linked units, and re-exports some variables +from the linked units for further linking. + +@; ------------------------------------------------------------------------ + +@section[#:tag "mz: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 "mz: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 "mz: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 "mz: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[ +(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 "mz: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[ +#:literals (-type -selectors -setters -constructor) +(struct id (field-id ...) omit-decl ...) + +([omit-decl + -type + -selectors + -setters + -constructor])]{ + +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-id ...))], except +that a @scheme[omit-decl] can cause some of the bindings to be +omitted. Specifically @scheme[-type] causes +@schemeidfont{struct:}@scheme[id] to be omitted, @scheme[-selectors] +causes all @scheme[id]@schemeidfont{-}@scheme[_field-id]s to be +omitted, @scheme[-setters] causes all +@schemeidfont{set-}@scheme[id]@schemeidfont{-}@scheme[field-id]@schemeidfont{!}s +to be omitted, and @scheme[-construct] causes +@schemeidfont{make-}@scheme[id] to be omitted. These omissions are +reflected in the static information bound to @scheme[id] (which is +used by, for example, pattern matchers).} + +@; ------------------------------------------------------------------------ + +@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].}