6.7 Modules and Macros

► |  | The Racket Guide

1 | Welcome to Racket
2 | Racket Essentials
3 | Built-In Datatypes
4 | Expressions and Definitions
5 | Programmer-Defined Datatypes
6 | Modules
7 | Contracts
8 | Input and Output
9 | Regular Expressions
10 | Exceptions and Control
11 | Iterations and Comprehensions
12 | Pattern Matching
13 | Classes and Objects
14 | Units
15 | Reflection and Dynamic Evaluation
16 | Macros
17 | Creating Languages
18 | Concurrency and Synchronization
19 | Performance
20 | Parallelism
21 | Running and Creating Executables
22 | More Libraries
23 | Dialects of Racket and Scheme
24 | Command-Line Tools and Your Editor of Choice
| Bibliography
| Index

▼ | 6 | Modules

6.1 | Module Basics
6.2 | Module Syntax
6.3 | Module Paths
6.4 | Imports: require
6.5 | Exports: provide
6.6 | Assignment and Redefinition
6.7 | Modules and Macros
6.8 | Protected Exports

top contents ← prev up next →

#### 6.7`` 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 Macros, but here’s a simple example of a module that defines a pattern-based macro:

> (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:

> > (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

> (define-noisy (f x y)
> (+ x y))

with

> (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 Compile and Run-Time Phases and Module Instantiations and Visits.

top contents ← prev up next →