You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
typesetting/quad/qtest/mds/macro-module.md

392 lines
16 KiB
Markdown

5 years ago
# 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 modules
top-level expressions include side effects, however, then the timing of
the effects can matter. The distinction between module declaration and
instantiation provides some control over that timing. The concept of
module visits further explains the interaction of effects with macro
implementations.
## 1. Declaration versus Instantiation
Declaring a module does not immediately evaluate expressions in the
modules body. For example, evaluating
```racket
> (module number-n racket/base
(provide n)
(define n (random 10))
(printf "picked ~a\n" n))
```
declares the module `number-n`, but it doesnt immediately pick a random
number for `n` or display the number. A `require` of `number-n` causes
the module to be _instantiated_ \(i.e., it triggers an
_instantiation_\), which implies that the expressions in the body of the
module are evaluated:
```racket
> (require 'number-n)
picked 5
> n
5
```
After a module is instantiated in a particular namespace, further
`require`s of the module use the same instance, as opposed to
instantiating the module again:
```racket
> (require 'number-n)
> n
5
> (module use-n racket/base
(require 'number-n)
(printf "still ~a\n" n))
> (require 'use-n)
still 5
```
The `dynamic-require` function, like `require`, triggers instantion of a
module if it is not already instantiated, so `dynamic-require` with `#f`
as a second argument is useful to just trigger the instantion effects of
a module:
```racket
> (module use-n-again racket/base
(require 'number-n)
(printf "also still ~a\n" n))
> (dynamic-require ''use-n-again #f)
also still 5
```
Instantiation of modules by `require` is transitive. That is, if
`require` of a module instantiates it, then any module `require`d by
that one is also instantiated \(if its not instantiated already\):
```racket
> (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)
picked 0
still 0
```
## 2. Compile-Time Instantiation
In the same way that declaring a module does not by itself instantiate a
module, declaring a module that `require`s another module does not by
itself instantiate the `require`d module, as illustrated in the
preceding example. However, declaring a module _does_ expand and compile
the module. If a module imports another with `(require (for-syntax
....))`, then module that is imported `for-syntax` must be instantiated
during expansion:
```racket
> (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)))
picked 1
```
Unlike run-time instantiation in a namespace, when a module is used
`for-syntax` for another module expansion in the same namespace, the
`for-syntax`ed module is instantiated separately for each expansion.
Continuing the previous example, if `number-p` is used a second time
`for-syntax`, then a second random number is selected for a new `p`:
```racket
> (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)))
picked 3
```
Separate compile-time instantiations of `number-p` helps prevent
accidental propagation of effects from one modules compilation to
another modules compilation. Preventing those effects make compilation
reliably separate and more deterministic.
The expanded forms of `use-p-at-compile-time` and
`use-p-again-at-compile-time` record the number that was selected each
time, so those two different numbers are printed when the modules are
instantiated:
```racket
> (dynamic-require ''use-p-at-compile-time #f)
was 1 at compile time
> (dynamic-require ''use-p-again-at-compile-time #f)
was 3 at second compile time
```
A namespaces 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 `(require (for-syntax ....))` twice in the
top level, the second use does not trigger a new compile-time instance:
```racket
> (begin (require (for-syntax 'number-p)) 'done)
picked 4
'done
> (begin (require (for-syntax 'number-p)) 'done-again)
'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-`for-syntax` use of `number-p` will pick another random number:
```racket
> (require 'number-p)
picked 5
```
## 3. Visiting Modules
When a module `provide`s a macro for use by other modules, the other
modules use the macro by directly `require`ing the macro provider—i.e.,
without `for-syntax`. Thats because the macro is being imported for use
in a run-time position \(even though the macros implementation lives at
compile time\), while `for-syntax` would import a binding for use in
compile-time position.
The module implementing a macro, meanwhile, might `require` another
module `for-syntax` to implement the macro. The `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 `require` that is similar to instantiation transitivity, but
“off by one” at the point where the `for-syntax` shift occurs in the
chain.
Heres an example to make that scenario concrete:
```racket
> (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)))
picked 7
> (module use-qm racket/base
(require 'use-q-at-compile-time)
(printf "was ~a at second compile time\n" (qm)))
picked 4
> (dynamic-require ''use-qm #f)
was 7 at compile time
was 4 at second compile time
```
In this example, when `use-q-at-compile-time` is expanded and compiled,
`number-q` is instantiated once. In this case, that instantion is needed
to expand the `(qm)` macro, but the module system would proactively
create a compile-time instantiation of `number-q` even if the `qm` macro
turned out not to be used.
Then, as `use-qm` is expanded and compiled, a second compile-time
instantiation of `number-q` is created. That compile-time instantion is
needed to expand the `(qm)` form within `use-qm`.
Instantiating `use-qm` correctly reports the number that was picked
during that second modules compilation. First, though, the `require` of
`use-q-at-compile-time` in `use-qm` triggers a transitive instantiation
of `use-q-at-compile-time`, which correctly reports the number that was
picked in its compilation.
Overall, the example illustrates a transitive effect of `require` that
we had already seen:
* When a module is instantiated, the run-time expressions in its
body are evaluated.
* When a module is instantiated, then any module that it `require`s
\(without `for-syntax`\) is also instantiated.
This rule does not explain the compile-time instantiations of
`number-q`, however. To explain that, we need a new word, _visit_, for
the concept that we saw in Compile-Time Instantiation:
* When a module is visited, the compile-time expressions \(such as
macro definition\) in its body are evaluated.
* As a module is expanded, it is visited.
* When a module is visited, then any module that it `require`s
\(without `for-syntax`\) is also visited.
* When a module is visited, then any module that it `require`s
`for-syntax` is instantiated at compile time.
Note that when visiting one module causes a compile-time instantion of
another module, the transitiveness of instantiated through regular
`require`s can trigger more compile-time instantiations. Instantiation
itself wont 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 visiting
include both the right-hand sides of `define-syntax` forms and the body
of `begin-for-syntax` forms. Thats why a randomly selected number is
printed immediately in the following example:
```racket
> (module compile-time-number racket/base
(require (for-syntax racket/base))
(begin-for-syntax
(printf "picked ~a\n" (random)))
(printf "running\n"))
picked 0.25549265186825576
```
Instantiating the module evaluates only the run-time expressions, which
prints “running” but not a new random number:
```racket
> (dynamic-require ''compile-time-number #f)
running
```
The description of instantiates and visit above is phrased in terms of
normal `require`s and `for-syntax` `require`s, but a more precise
specification is in terms of module phases. For example, if module `A`
has `(require (for-syntax B))` and module `B` has `(require
(for-template C))`, then module `C` is instantiated when module `A` is
instantiated, because the `for-syntax` and `for-template` shifts cancel.
We have not yet specified what happens with `for-meta 2` for when
`for-syntax`es combine; we leave that to the next section, Lazy Visits
via Available Modules.
If you think of the top-level as a kind of module that is continuously
expanded, the above rules imply that `require` of another module at the
top level both instantiates and visits the other module \(if it is not
already instantiated and visited\). Thats roughly true, but the visit
is made lazy in a way that is also explained in the next section, Lazy
Visits via Available Modules.
Meanwhile, `dynamic-require` only instantiates a module; it does not
visit the module. That simplification is why some of the preceding
examples use `dynamic-require` instead of `require`. The extra visits of
a top-level `require` would make the earlier examples less clear.
## 4. Lazy Visits via Available Modules
A top-level `require` of a module does not actually visit the module.
Instead, it makes the module _available_. An available module will be
visited 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 its compile-time helpers evaluated by visiting, but the
module system proactively visits the module, just in case.
In the following example, a random number is picked as a result of
visiting a modules own body while that module is being expanded. A
`require` of the module instantiates it, printing “running”, and also
makes the module available. Evaluating any other expression implies
expanding the expression, and that expansion triggers a visit of the
available module—which picks another random number:
```racket
> (module another-compile-time-number racket/base
(require (for-syntax racket/base))
(begin-for-syntax
(printf "picked ~a\n" (random)))
(printf "running\n"))
picked 0.3634379786893492
> (require 'another-compile-time-number)
running
> 'next
picked 0.5057086679589476
'next
> 'another
'another
```
> Beware that the expander flattens the content of a top-level `begin`
> into the top level as soon as the `begin` is discovered. So, `(begin
> (require 'another-compile-time-number) 'next)` would still have printed
> “picked” before “next“.
The final evaluation of `'another` also visits any available modules,
but no modules were made newly available by simply evaluating `'next`.
When a module `require`s another module using `for-meta n` for some `n`
greater than 1, the `require`d module is made available at phase `n`. A
module that is available at phase `n` is visited when some expression at
phase `n`_-_1__ is expanded.
To help illustrate, the following examples use
`(variable-reference->module-base-phase (#%variable-reference))`, which
returns a number for the phase at which the enclosing module is
instantiated:
```racket
> (module show-phase racket/base
(printf "running at ~a\n"
(variable-reference->module-base-phase (#%variable-reference))))
> (require 'show-phase)
running at 0
> (module use-at-phase-1 racket/base
(require (for-syntax 'show-phase)))
running at 1
> (module unused-at-phase-2 racket/base
(require (for-meta 2 'show-phase)))
```
For the last module above, `show-phase` is made available at phase 2,
but no expressions within the module are ever expanded at phase 1, so
theres no phase-2 printout. The following module includes a phase-1
expression after the phase-2 `require`, so theres a printout:
```racket
> (module use-at-phase-2 racket/base
(require (for-meta 2 'show-phase)
(for-syntax racket/base))
(define-syntax x 'ok))
running at 2
```
If we `require` the module `use-at-phase-1` at the top level, then
`show-phase` is made available at phase 1. Evaluating another expression
causes `use-at-phase-1` to be visited, which in turn instantitates
`show-phase`:
```racket
> (require 'use-at-phase-1)
> 'next
running at 1
'next
```
A `require` of `use-at-phase-2` is similar, except that `show-phase` is
made available at phase 2, so it is not instantiated until some
expression is expanded at phase 1:
```racket
> (require 'use-at-phase-2)
> 'next
'next
> (require (for-syntax racket/base))
> (begin-for-syntax 'compile-time-next)
running at 2
```