Clojure Macros Tutorial - part 3: Syntax Quote (aka Backtick) in Clojure 【转载】
Clojure Macros Tutorial - part 3: Syntax Quote (aka Backtick) in Clojure
May 5, 2016 clojure
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:
- fully-qualified symbols
- unquote with
~
- unquote splicing with
~@
- 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…
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)
the evaluation will appear here (soon)...
'(a (b (c d (e f (g h) i) j)))
the evaluation will appear here (soon)...
'{:a (1 2 3) b (c d "x")}
the evaluation will appear here (soon)...
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)
the evaluation will appear here (soon)...
While with syntax quote, the symbol is resolved:
`(map)
the evaluation will appear here (soon)...
If a symbol exists in the current namespace, it is resolved there:
(ns my.quote)
(def a 123)
`(a)
the evaluation will appear here (soon)...
If a symbol cannot be resolved, it is also resolved in the current namespace:
`(b)
the evaluation will appear here (soon)...
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))
the evaluation will appear here (soon)...
With evaluation:
`(16 17 ~(inc 17))
the evaluation will appear here (soon)...
Another one:
`(16 17 ~(map inc [16 17]))
the evaluation will appear here (soon)...
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]))
the evaluation will appear here (soon)...
With splicing:
`(16 17 ~@(map inc [16 17]))
the evaluation will appear here (soon)...
Other examples:
`(1 2 ~@[1 [2 3]])
the evaluation will appear here (soon)...
`(1 2 ~@#{1 2 3})
the evaluation will appear here (soon)...
`(1 2 ~@{:a 1 :b 2 :c 3})
the evaluation will appear here (soon)...
Syntax Quote - symbol generation
Inside syntax quote, you can generate unique symbol names by appending #
to the symbol.
`(A#)
the evaluation will appear here (soon)...
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#)
the evaluation will appear here (soon)...
`(a b a# b# a# b#)
the evaluation will appear here (soon)...
`{:a a# :b b# :c b#}
the evaluation will appear here (soon)...
There are other advanced features available inside syntax quote like ~'
, ~~
and '~@
.
We might write an article on it in the (near) future…
Clojure rocks!
Subscribe to Yehonathan Sharvit newsletter
Get the latest and greatest from Yehonathan Sharvit delivered straight to your inbox every week.
Email Address
READ NEXT
May 4, 2016
Clojure Macros Tutorial - part 2: how not to write macros
May 9, 2016
Clojure Macros Tutorial - part 4: Examples of cool macros #cljklipse @viebel
TAGS
algo brainfuck c++ clojure clojurescript compiler dop golang graph html java javascript kids klipse lambda-calculus lambdacalculus lisp lua maths oblivion ocaml php prolog python react reagent reasonml ruby scheme sql theory visualization
YEHONATHAN SHARVIT © 2022.