Clojure provides a powerful tool to allow the developer to write macros effectively. This tool is called “Syntax quote”.

This tool provide an elegant solution to the issues mentioned in how not to write macros in Clojure.

Syntax quote has 4 powerful features:

  1. fully-qualified symbols
  2. unquote with ~
  3. unquote splicing with ~@
  4. generated symbols with #

Here is the official documentation for syntax quote.

But this documentation is too cryptic.

In this article, we present this powerful tool in a much digestible way…

Dummies

Regular Quote

Before dealing with syntax quoting, let’s remember how the regular quote works.

There are two equivalent ways to quote a form either with quote or with '. The latter is much more convenient so we will use it.

It works recursively with any kind of forms and types: strings, maps, lists, vectors…

Let’s have a look at some examples:

'(a :a 1)
'(a (b (c d (e f (g h) i) j)))
'{:a (1 2 3) b (c d "x")}

Syntax Quote - symbol resolution

Syntax quote is done with a backtick `. It quotes a form and resolves symbols in the current context yielding a fully-qualified symbol. If the symbol doesn’t exist in the current namespace, it is resolved to the current namespace.

When we use the regular quote, there is no namespace resolution:

'(map)

While with syntax quote, the symbol is resolved:

`(map)

If a symbol exists in the current namespace, it is resolved there:

(ns my.quote)
(def a 123)
`(a)

If a symbol cannot be resolved, it is also resolved in the current namespace:

`(b)

Syntax Quote - unquote

With syntax quote, it’s possible to unquote part of the form that is quoted with ~. It allows you to evaluate part of the expression.

Without evaluation:

`(16 17 (inc 17))

With evaluation:

`(16 17 ~(inc 17))

Another one:

`(16 17 ~(map inc [16 17]))

Syntax Quote - unquote splicing

But what if you want to unquote a list and insert its elements (not the list) inside the quoted form?

No problem, ~@ is your friend (his official name is unquote splicing). And ~@ is really a good friend as he knows to handle any kind of collection.

Without splicing:

 `(16 17 ~(map inc [16 17]))

With splicing:

`(16 17 ~@(map inc [16 17]))

Other examples:

`(1 2 ~@[1 [2 3]])
`(1 2 ~@#{1 2 3})
`(1 2 ~@{:a 1 :b 2 :c 3})

Syntax Quote - symbol generation

Inside syntax quote, you can generate unique symbol names by appending # to the symbol.

`(A#)

The cool thing is that all the references to that symbol within a syntax-quoted expression resolve to the same generated symbol.

`(a b a# b#)
`(a b a# b# a# b#)
`{:a a# :b b# :c b#}

There are other advanced features available inside syntax quote like ~', ~~and '~@.

We might write an article on it in the (near) future…

Clojure rocks!