racket/pkgs/racket-doc/scribblings/guide/macro-module.scrbl
2018-04-18 11:07:46 -05:00

448 lines
15 KiB
Racket

#lang scribble/manual
@(require scribble/manual
scribble/examples
"guide-utils.rkt")
@(define visit-eval (make-base-eval))
@examples[
#:hidden
#:eval visit-eval
(current-pseudo-random-generator (make-pseudo-random-generator))
;; Make the output deterministic:
(random-seed 11)
]
@title[#:tag "macro-module"]{Module Instantiations and Visits}
Modules often contain just function and structure-type definitions, in
which case the module itself behaves in a purely functional way, and
the time when the functions are created is not observable. If a
module's top-level expressions include side effects, however, then the
timing of the effects can matter. The distinction between module
declaration and @tech{instantiation} provides some control over that
timing. The concept of module @tech{visits} further explains the
interaction of effects with macro implementations.
@; ----------------------------------------
@section{Declaration versus Instantiation}
Declaring a module does not immediately evaluate expressions in the
module's body. For example, evaluating
@examples[
#:label #f
#:eval visit-eval
(module number-n racket/base
(provide n)
(define n (random 10))
(printf "picked ~a\n" n))
]
declares the module @racket[number-n], but it doesn't immediately pick a
random number for @racket[n] or display the number. A @racket[require]
of @racket[number-n] causes the module to be @deftech{instantiated}
(i.e., it triggers an @deftech{instantiation}), which implies that the
expressions in the body of the module are evaluated:
@examples[
#:label #f
#:eval visit-eval
(require 'number-n)
n
]
After a module is instantiated in a particular @tech{namespace},
further @racket[require]s of the module use the same instance, as
opposed to instantiating the module again:
@examples[
#:label #f
#:eval visit-eval
(require 'number-n)
n
(module use-n racket/base
(require 'number-n)
(printf "still ~a\n" n))
(require 'use-n)
]
The @racket[dynamic-require] function, like @racket[require], triggers
instantion of a module if it is not already instantiated, so
@racket[dynamic-require] with @racket[#f] as a second argument is
useful to just trigger the instantion effects of a module:
@examples[
#:label #f
#:eval visit-eval
(module use-n-again racket/base
(require 'number-n)
(printf "also still ~a\n" n))
(dynamic-require ''use-n-again #f)
]
Instantiation of modules by @racket[require] is transitive. That is,
if @racket[require] of a module instantiates it, then any module
@racket[require]d by that one is also instantiated (if it's not
instantiated already):
@examples[
#:label #f
#:eval visit-eval
(module number-m racket/base
(provide m)
(define m (random 10))
(printf "picked ~a\n" m))
(module use-m racket/base
(require 'number-m)
(printf "still ~a\n" m))
(require 'use-m)
]
@; ----------------------------------------
@section[#:tag "compile-time-instantiation"]{Compile-Time Instantiation}
In the same way that declaring a module does not by itself instantiate
a module, declaring a module that @racket[require]s another module
does not by itself instantiate the @racket[require]d module, as
illustrated in the preceding example. However, declaring a module
@emph{does} expand and compile the module. If a module imports another
with @racket[(require (for-syntax ....))], then module that is
imported @racket[for-syntax] must be instantiated during expansion:
@examples[
#:label #f
#:eval visit-eval
#:escape UNSYNTAX
(module number-p racket/base
(provide p)
(define p (random 10))
(printf "picked ~a\n" p))
(module use-p-at-compile-time racket/base
(require (for-syntax racket/base
'number-p))
(define-syntax (pm stx)
#`#,p)
(printf "was ~a at compile time\n" (pm)))
]
Unlike run-time instantiation in a namespace, when a module is used
@racket[for-syntax] for another module expansion in the same
namespace, the @racket[for-syntax]ed module is instantiated separately
for each expansion. Continuing the previous example, if
@racket[number-p] is used a second time @racket[for-syntax], then a
second random number is selected for a new @racket[p]:
@examples[
#:label #f
#:eval visit-eval
#:escape UNSYNTAX
(module use-p-again-at-compile-time racket/base
(require (for-syntax racket/base
'number-p))
(define-syntax (pm stx)
#`#,p)
(printf "was ~a at second compile time\n" (pm)))
]
Separate compile-time instantiations of @racket[number-p] helps
prevent accidental propagation of effects from one module's
compilation to another module's compilation. Preventing those effects
make compilation reliably separate and more deterministic.
The expanded forms of @racket[use-p-at-compile-time] and
@racket[use-p-again-at-compile-time] record the number that was
seelcted each time, so those two different numbes are printed when the
modules are instantiated:
@examples[
#:label #f
#:eval visit-eval
(dynamic-require ''use-p-at-compile-time #f)
(dynamic-require ''use-p-again-at-compile-time #f)
]
A namespace's top level behaves like a separate module, where multiple
interactions in the top level conceptually extend a single expansion
of the module. So, when using @racket[(require (for-syntax ....))]
twice in the top level, the second use does not trigger a new
compile-time instance:
@examples[
#:label #f
#:eval visit-eval
(begin (require (for-syntax 'number-p)) 'done)
(begin (require (for-syntax 'number-p)) 'done-again)
]
However, a run-time instance of a module is kept separate from all
compile-time instances, including at the top level, so a
non-@racket[for-syntax] use of @racket[number-p] will pick another
random number:
@examples[
#:label #f
#:eval visit-eval
(require 'number-p)
]
@; ----------------------------------------
@section{Visiting Modules}
When a module @racket[provide]s a macro for use by other modules, the
other modules use the macro by directly @racket[require]ing the macro
provider---i.e., without @racket[for-syntax]. That's because the macro
is being imported for use in a run-time position (even though the
macro's implementation lives at compile time), while
@racket[for-syntax] would import a binding for use in compile-time
position.
The module implementing a macro, meanwhile, might @racket[require]
another module @racket[for-syntax] to implement the macro. The
@racket[for-syntax] module needs a compile-time instantiation during
any module expansion that might use the macro. That requirement sets
up a kind of transitivity through @racket[require] that is similar to
instantiation transitivity, but ``off by one'' at the point where the
@racket[for-syntax] shift occurs in the chain.
Here's an example to make that scenario concrete:
@examples[
#:label #f
#:eval visit-eval
#:escape UNSYNTAX
(module number-q racket/base
(provide q)
(define q (random 10))
(printf "picked ~a\n" q))
(module use-q-at-compile-time racket/base
(require (for-syntax racket/base
'number-q))
(provide qm)
(define-syntax (qm stx)
#`#,q)
(printf "was ~a at compile time\n" (qm)))
(module use-qm racket/base
(require 'use-q-at-compile-time)
(printf "was ~a at second compile time\n" (qm)))
(dynamic-require ''use-qm #f)
]
In this example, when @racket[use-q-at-compile-time] is expanded and
compiled, @racket[number-q] is instantiated once. In this case, that
instantion is needed to expand the @racket[(qm)] macro, but the module
system would proactively create a compile-time instantiation of
@racket[number-q] even if the @racket[qm] macro turned out not to be
used.
Then, as @racket[use-qm] is expanded and compiled, a second
compile-time instantiation of @racket[number-q] is created. That
compile-time instantion is needed to expand the @racket[(qm)] form
within @racket[use-qm].
Instantiating @racket[use-qm] correctly reports the number that was
picked during that second module's compilation. First, though, the
@racket[require] of @racket[use-q-at-compile-time] in @racket[use-qm]
triggers a transitive instantiation of @racket[use-q-at-compile-time],
which correctly reports the number that was picked in its compilation.
Overall, the example illustrates a transitive effect of
@racket[require] that we had already seen:
@itemlist[
@item{When a module is @tech{instantiated}, the run-time expressions
in its body are evaluated.}
@item{When a module is @tech{instantiated}, then any module that it @racket[require]s
(without @racket[for-syntax]) is also @tech{instantiated}.}
]
This rule does not explain the compile-time instantiations of
@racket[number-q], however. To explain that, we need a new word,
@deftech{visit}, for the concept that we saw in
@secref["compile-time-instantiation"]:
@itemlist[
@item{When a module is @tech{visit}ed, the compile-time expressions
(such as macro definition) in its body are evaluated.}
@item{As a module is expanded, it is @tech{visit}ed.}
@item{When a module is @tech{visit}ed, then any module that it @racket[require]s
(without @racket[for-syntax]) is also @tech{visit}ed.}
@item{When a module is @tech{visit}ed, then any module that it @racket[require]s
@racket[for-syntax] is @tech{instantiated} at compile time.}
]
Note that when visiting one module causes a compile-time instantion of
another module, the transitiveness of @tech{instantiated} through
regular @racket[require]s can trigger more compile-time instantiations.
Instantiation itself won't trigger further visits, however, because
any instantiated module has already been expanded and compiled.
The compile-time expressions of a module that are evaluated by
@tech{visit}ing include both the right-hand sides of
@racket[define-syntax] forms and the body of @racket[begin-for-syntax]
forms. That's why a randomly selected number is printed immediately in
the following example:
@examples[
#:label #f
#:eval visit-eval
(module compile-time-number racket/base
(require (for-syntax racket/base))
(begin-for-syntax
(printf "picked ~a\n" (random)))
(printf "running\n"))
]
Instantiating the module evaluates only the run-time expressions,
which prints ``running'' but not a new random number:
@examples[
#:label #f
#:eval visit-eval
(dynamic-require ''compile-time-number #f)
]
The description of @tech{instantiates} and @tech{visit} above is
phrased in terms of normal @racket[require]s and @racket[for-syntax]
@racket[require]s, but a more precise specification is in terms of
module phases. For example, if module @racket[_A] has @racket[(require
(for-syntax _B))] and module @racket[_B] has @racket[(require
(for-template _C))], then module @racket[_C] is @tech{instantiated}
when module @racket[_A] is instantiated, because the
@racket[for-syntax] and @racket[for-template] shifts cancel. We have
not yet specified what happens with @racket[for-meta 2] for when
@racket[for-syntax]es combine; we leave that to the next section,
@secref["stx-available-module"].
If you think of the top-level as a kind of module that is continuously
expanded, the above rules imply that @racket[require] of another
module at the top level both instantiates and visits the other module
(it it is not already instantiated and visited). That's roughly true,
but the visit is made lazy in a way that is also explained in the next
section, @secref["stx-available-module"].
Meanwhile, @racket[dynamic-require] only instantiates a module; it
does not visit the module. That simplification is why some of the
preceding examples use @racket[dynamic-require] instead of
@racket[require]. The extra visits of a top-level @racket[require]
would make the earlier examples less clear.
@; ----------------------------------------
@section[#:tag "stx-available-module"]{Lazy Visits via Available Modules}
A top-level @racket[require] of a module does not actually
@tech{visit} the module. Instead, it makes the module
@deftech{available}. An @tech{available} module will be @tech{visit}ed
when a future expression needs to be expanded in the same context. The
next expression may or may not involve some imported macro that needs
it's compile-time helpers evaluated by @tech{visit}ing, but the module
system proactively @tech{visit}s the module, just in case.
In the following example, a random number is picked as a result of
visiting a module's own body while that module is being expanded. A
@racket[require] of the module instantiates it, printing ``running'',
and also makes the module @tech{available}. Evaluating any other
expression implies expanding the expression, and that expansions
triggers a @tech{visit} of the @tech{available} module---which picks
another random number:
@examples[
#:label #f
#:eval visit-eval
(module another-compile-time-number racket/base
(require (for-syntax racket/base))
(begin-for-syntax
(printf "picked ~a\n" (random)))
(printf "running\n"))
(require 'another-compile-time-number)
'next
'another
]
@margin-note{Beware that the expander flattens the content of a
top-level @racket[begin] into the top level as soon as the
@racket[begin] is discovered. So, @racket[(begin (require
'another-compile-time-number) 'next)] would still have printed
``picked'' before ``next``.}
The final evaluation of @racket['another] also visits any available
modules, but no modules were made newly available by simply evaluating
@racket['next].
When a module @racket[require]s another module using @racket[for-meta
_n] for some @racket[_n] greater than 1, the @racket[require]d module
is made @tech{available} at phase @racket[_n]. A module that is
@tech{available} at phase @racket[_n] is @tech{visit}ed some some
expression at phase @math{@racket[_n]-1} is expanded.
To help illustrate, the following examples use
@racket[(variable-reference->module-base-phase
(#%variable-reference))], which returns a number for the phase at
which the enclosing module is instaniated:
@examples[
#:label #f
#:eval visit-eval
(module show-phase racket/base
(printf "running at ~a\n"
(variable-reference->module-base-phase (#%variable-reference))))
(require 'show-phase)
(module use-at-phase-1 racket/base
(require (for-syntax 'show-phase)))
(module unused-at-phase-2 racket/base
(require (for-meta 2 'show-phase)))
]
For the last module above, @racket[show-phase] is made
@tech{available} at phase 2, but no expressions within the module are
ever expanded at phase 1, so there's no phase-2 printout. The
following module includes a phase-1 expression after the phase-2
@racket[require], so there's a printout:
@examples[
#:label #f
#:eval visit-eval
(module use-at-phase-2 racket/base
(require (for-meta 2 'show-phase)
(for-syntax racket/base))
(define-syntax x 'ok))
]
If we @racket[require] the module @racket[use-at-phase-1] at the top
level, then @racket[show-phase] is made @tech{available} at phase 1.
Evaluating another expression causes @racket[use-at-phase-1] to be
@tech{visit}ed, which in turn instanitates @racket[show-phase]:
@examples[
#:label #f
#:eval visit-eval
(require 'use-at-phase-1)
'next
]
A @racket[require] of @racket[use-at-phase-2] is similar, except that
@racket[show-phase] is made @tech{available} at phase 2, so it is not
instaniated until some expression is expanded at phase 1:
@examples[
#:label #f
#:eval visit-eval
(require 'use-at-phase-2)
'next
(require (for-syntax racket/base))
(begin-for-syntax 'compile-time-next)
]
@; ----------------------------------------------------------------------
@close-eval[visit-eval]