6

Clojure Macros Tutorial - part 3: Syntax Quote (aka Backtick) in Clojure

 3 years ago
source link: https://blog.klipse.tech/clojure/2016/05/05/macro-tutorial-3.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Clojure Macros Tutorial - part 3: Syntax Quote (aka Backtick) in Clojure

May 5, 2016 • Yehonathan Sharvit

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:

xxxxxxxxxx
'(a :a 1)
the evaluation will appear here (soon)...
xxxxxxxxxx
'(a (b (c d (e f (g h) i) j)))
xxxxxxxxxx
the evaluation will appear here (soon)...
xxxxxxxxxx
'{:a (1 2 3) b (c d "x")}
xxxxxxxxxx
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:

xxxxxxxxxx
'(map)
xxxxxxxxxx
the evaluation will appear here (soon)...

While with syntax quote, the symbol is resolved:

xxxxxxxxxx
`(map)
xxxxxxxxxx
the evaluation will appear here (soon)...

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

xxxxxxxxxx
(ns my.quote)
(def a 123)
`(a)
xxxxxxxxxx
the evaluation will appear here (soon)...

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

xxxxxxxxxx
`(b)
xxxxxxxxxx
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:

xxxxxxxxxx
`(16 17 (inc 17))
xxxxxxxxxx
the evaluation will appear here (soon)...

With evaluation:

xxxxxxxxxx
`(16 17 ~(inc 17))
xxxxxxxxxx
the evaluation will appear here (soon)...

Another one:

xxxxxxxxxx
`(16 17 ~(map inc [16 17]))
xxxxxxxxxx
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:

xxxxxxxxxx
`(16 17 ~(map inc [16 17]))
xxxxxxxxxx
the evaluation will appear here (soon)...

With splicing:

xxxxxxxxxx
`(16 17 ~@(map inc [16 17]))
xxxxxxxxxx
the evaluation will appear here (soon)...

Other examples:

xxxxxxxxxx
`(1 2 ~@[1 [2 3]])
xxxxxxxxxx
the evaluation will appear here (soon)...
xxxxxxxxxx
`(1 2 ~@#{1 2 3})
xxxxxxxxxx
the evaluation will appear here (soon)...
xxxxxxxxxx
`(1 2 ~@{:a 1 :b 2 :c 3})
xxxxxxxxxx
the evaluation will appear here (soon)...

Syntax Quote - symbol generation

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

xxxxxxxxxx
`(A#)
xxxxxxxxxx
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.

xxxxxxxxxx
`(a b a# b#)
xxxxxxxxxx
the evaluation will appear here (soon)...
xxxxxxxxxx
`(a b a# b# a# b#)
xxxxxxxxxx
the evaluation will appear here (soon)...
xxxxxxxxxx
`{:a a# :b b# :c b#}
xxxxxxxxxx
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!

If you enjoy this kind of interactive articles would you consider a (small) donation💸 on Patreon or at least giving a star⭐ for the Klispe repo on Github?

to stay up-to-date with the coolest interactive articles around the world.

Discover more cool interactive articles about javascript, clojure[script], python, ruby, scheme, c++ and even brainfuck!

Give Klipse a Github star to express how much you appreciate Code Interactivity.

Subscribe to the Klipse newsletter:

Feel free to email me [email protected] for getting practical tips and tricks in writing your first interactive blog post.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK