Safari Books Online is a digital library providing on-demand subscription access to thousands of learning resources.
Macro basics 149 This chapter discusses macros are and how to use them. We'll begin by writing an example macro, which will help you explore Clojure's macro-writing facilities. Then, we'll dig into the Clojure source code to examine a few well-written macros. It's inspiring to learn that parts of Clojure itself are written as macros and that you can use this facility in your own programs. Finally, you'll write a few macros of your own. We'll begin with explaining what a macro is and why a language might need a macro system. 7.1 Macro basics In order to explain what a macro is, we'll take a step back and examine language run- times again. Recall from chapter 1 that the Clojure runtime processes source code dif- ferently when compared to most other languages. Specifically, there's a read phase followed by an evaluation phase. In the first phase, the Clojure reader converts a stream of characters (the source code) into Clojure data structures. These data struc- tures are then evaluated to execute the program. The trick that makes macros possi- ble is that Clojure offers a hook between the two phases, allowing the programmer to process the data structures representing the code before they're evaluated. Figure 7.1, which you also saw in chapter 1, illustrates these phases. Code is converted into data structures and these data structures are then evalu- ated. Macros are functions that the programmer can write that act upon these data structures before they're evaluated. Macros allow code to be modified programmati- cally before evaluation, making it possible to create whole new kinds of abstractions. Macros operate at the syntactic level by operating on the code itself. Consequently, you can use them to add features to the Clojure language itself. You'll see examples of this in this chapter. 7.1.1 Textual substitution As an example, imagine that you had a ref called a-ref : (def a-ref (ref 0)) Now, imagine that you wanted to change the value of a-ref to 1. You might do some- thing like this: (dosync (ref-set a-ref 1)) Figure 7.1 Phases of the Clojure runtime. This separation is what makes the macro system possible.