### PCL -> Clojure, Chapter 8

This article is part of a series describing a port of the samples from Practical Common Lisp (PCL) to Clojure. You will probably want to read the intro first.

This article covers Chapter 8, Macros: Defining Your Own.

## Rolling your own

Lisp macros gain their power by controlling argument evaluation. In a normal Lisp function all arguments are evaluated when calling a function. Consider this call to function `foo`

:

(foo a b)

Arguments `a`

and `b`

are evaluated, and then passed to function `foo`

. If `foo`

were a macro, however, all bets would be off. Then `foo`

's arguments might be evaluated in bizarre orders, or not at all.

This may seem a little crazy until you consider a simple `if`

:

` (if monday (wake-up) (sleep))`

`if`

cannot possibly be a normal Lisp function. If it were, you would always both `wake-up`

*and* `sleep`

, regardless of the value of `monday`

.

As the `if`

example suggests, control flow is an obvious use case for macros. PCL demonstrates custom macros by defining a new control flow macro named `do-primes`

.

## Preparing for do-primes

In order to implement `do-primes`

, I will need a primeness test. For clarity, I will divide this into two functions. First, a simple helper to detect factors.

(defn divides? [candidate-divisor dividend] (zero? (rem dividend candidate-divisor)))

Now I can tell when one number divides another:

user=> (divides? 7 42) true user=> (divides? 11 42) false

A prime is simply a number with no divisors greater than one. I am a busy guy, so I won't check all the natural numbers, only those from two up to the square root of the number being tested. Here is a simple primeness test:

; yes, I know there are faster ways. (defn prime? [num] (when (> num 1) (every? (fn [x] (not (divides? x num))) (range 2 (inc (int (Math/sqrt num)))))))

## Sequences of primes

My eventual objective is to call `do-primes`

like this:

(do-primes i 100 200 (print (format "%d " i)))

where `i`

is the loop variable and runs the primes from `100`

to `200`

. Because Clojure has nice support for infinite sequences, I find it easier to begin by thinking in terms of the pure math. So, here is a function that returns the sequence of primes starting from a number:

(defn primes-from [number] (filter prime? (iterate inc number)))

`(iterate inc number)`

returns an infinite sequence starting with `number`

and then incrementing by one for each subsequent element. The `filter`

then whittles this down to numbers that are prime.

This sequence is infinite, so don't try to view it from the console. Take your primes a few at the time:

user=> (take 5 (primes-from 1000)) (1009 1013 1019 1021 1031)

Now I need a simple helper that begins with `primes-from`

, but cuts off the sequence at a chosen `end`

:

(defn primes-in-range [start end] (for [x (primes-from start) :while (<= x end)] x))

The `for`

is a list comprehension. It takes all the `(primes-from start)`

, but only `while`

those numbers are still less than or equal to `end`

.

## do-primes

Now I am finally ready to write the macro `do-primes`

:

(defmacro do-primes [var start end & body] `(doseq [~var (primes-in-range ~start ~end)] ~@body))

Macros work in two steps: expansion followed by normal Lisp evaluation. The expansion phase is like a template substitution, but with the full power of Lisp at your disposal.

In the definition of `do-primes`

above, the syntax-quote (`\`

`) identifies the *static* part of the template:

- For symbols, syntax-quote resolves the name to a fully qualified symbol (with some exceptions we don't need to worry about in this example).
- For lists, syntax-quote will recursively syntax-quote the contained forms.

The unquote (`~`

) and splicing-unquote (`~@`

) provide the *dynamic* part of the template by exempting their forms from syntax quoting rules.

Your reaction at this point should be "That's a lot of ugly punctuation." Fear not, `macroexpand-1`

will ease the pain. `macroexpand-1`

will show you how Clojure expands the macro, without executing the expanded result. This gives you a chance to experiment with the rules for quoting and unquoting. Here is an example:

user=> (macroexpand-1 '(do-primes i 1 10 (print i))) (clojure/doseq i (pcl.chap_08/primes-in-range 1 10) (print i))

Looking back at the definition of `do-primes`

, here is what happened:

`doseq`

expanded to the fully-qualified`clojure/doseq`

. (I haven't covered namespaces yet, but the`clojure`

namespace contains most of the Clojure core.)`i`

,`1`

, and`10`

are direct expansions from the macro call.`primes-in-range`

is one of the helper functions I wrote earlier. In the sample repository, I have placed this in the`pcl/chap_08`

namespace, hence the expansion.`body`

contains a list of things I want to do with my primes, specifically`((print i))`

. That is almost what I need, except a few too many parens. The "splice" part of splicing unquote gets rid of the extra parens, splicing the list into the template. This is exactly what I need to match the`doseq`

signature.

Now I can `do-primes`

:

user=> (do-primes i 100 150 (print (format "%d " i))) 101 103 107 109 113 127 131 137 139 149

## Wrapping up

The easiest way to write a macro is to work backwards. Write the form that you want the macro to expand into, and then test interactively with `macroexpand-1`

until you have a macro that expends correctly.

Macros are hard, and I have skipped some of the building blocks here. Check out the chapter in PCL.

### Notes

The sample code is available at http://github.com/stuarthalloway/practical-cl-clojure.

### Revision history

- 2008/09/23: initial version
- 2008/11/24: Updated to the new uniform binding syntax

## Responses

blog comments powered by Disqus