|
|
|
|
# Modules and Macros
|
|
|
|
|
|
|
|
|
|
Racket’s module system cooperates closely with Racket’s macro system for
|
|
|
|
|
adding new syntactic forms to Racket. For example, in the same way that
|
|
|
|
|
importing `racket/base` introduces syntax for `require` and `lambda`,
|
|
|
|
|
importing other modules can introduce new syntactic forms \(in addition
|
|
|
|
|
to more traditional kinds of imports, such as functions or constants\).
|
|
|
|
|
|
|
|
|
|
We introduce macros in more detail later, in \[missing\], but here’s a
|
|
|
|
|
simple example of a module that defines a pattern-based macro:
|
|
|
|
|
|
|
|
|
|
```racket
|
|
|
|
|
(module noisy racket
|
|
|
|
|
(provide define-noisy)
|
|
|
|
|
|
|
|
|
|
(define-syntax-rule (define-noisy (id arg ...) body)
|
|
|
|
|
(define (id arg ...)
|
|
|
|
|
(show-arguments 'id (list arg ...))
|
|
|
|
|
body))
|
|
|
|
|
|
|
|
|
|
(define (show-arguments name args)
|
|
|
|
|
(printf "calling ~s with arguments ~e" name args)))
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
The `define-noisy` binding provided by this module is a macro that acts
|
|
|
|
|
like `define` for a function, but it causes each call to the function to
|
|
|
|
|
print the arguments that are provided to the function:
|
|
|
|
|
|
|
|
|
|
```racket
|
|
|
|
|
> (require 'noisy)
|
|
|
|
|
> (define-noisy (f x y)
|
|
|
|
|
(+ x y))
|
|
|
|
|
> (f 1 2)
|
|
|
|
|
calling f with arguments '(1 2)
|
|
|
|
|
3
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Roughly, the `define-noisy` form works by replacing
|
|
|
|
|
|
|
|
|
|
```racket
|
|
|
|
|
(define-noisy (f x y)
|
|
|
|
|
(+ x y))
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
with
|
|
|
|
|
|
|
|
|
|
```racket
|
|
|
|
|
(define (f x y)
|
|
|
|
|
(show-arguments 'f (list x y))
|
|
|
|
|
(+ x y))
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Since `show-arguments` isn’t provided by the `noisy` module, however,
|
|
|
|
|
this literal textual replacement is not quite right. The actual
|
|
|
|
|
replacement correctly tracks the origin of identifiers like
|
|
|
|
|
`show-arguments`, so they can refer to other definitions in the place
|
|
|
|
|
where the macro is defined—even if those identifiers are not available
|
|
|
|
|
at the place where the macro is used.
|
|
|
|
|
|
|
|
|
|
There’s more to the macro and module interaction than identifier
|
|
|
|
|
binding. The `define-syntax-rule` form is itself a macro, and it expands
|
|
|
|
|
to compile-time code that implements the transformation from
|
|
|
|
|
`define-noisy` into `define`. The module system keeps track of which
|
|
|
|
|
code needs to run at compile and which needs to run normally, as
|
|
|
|
|
explained more in \[missing\] and \[missing\].
|