8
votes

I am trying to build datalog queries programmatically, but keep running into the problem that I will illustrate with an example function:

(defn test-expr [attribute]
  `[?entity ~attribute ?value]])

When I run (test-expr 3), I would expect the output:

 [?entity 3 ?value]

But instead, I get

[mynamespace/?entity 3 mynamespace/?value]

Which obviously is not what I want. Is there a way to tell clojure "please just quote the list and expand variables I tell you to?"

2
As to the reason why, it's to prevent users (cough you) from accidentally breaking your macros by defining functions and/or variables with the same name you're using.Cubic
@Cubic, agreed. As far as I understand, this is some kind of compromise between Scheme hygienic macros and Common Lisp plain macro systems: macro definitions look nearly exactly like Common Lisp ones (this is good, since Scheme macros are harder to write IMO), but by default there is certain level of hygiene present - symbols are not captured blindly but are prefixed with namespace instead. And it is always possible to fall back to plain substitutions when needed (e.g. for anaphoric macros).Vladimir Matveev

2 Answers

11
votes

Yes, there is.

(defn test-expr [attribute]
  `[~'?entity ~attribute ~'?value])

Here you first unquote the syntax quotation and then immediately quote the symbol (~' construct) again. The result is namespace-less symbol.

It is equivalent to the following, which explains how it works:

(defn test-expr [attribute]
  `[~(quote ?entity) ~attribute ~(quote ?value)])
6
votes

What you're looking for is the backtick library by Brandon Bloom https://github.com/brandonbloom/backtick

It was built for the exact problem you describe. It supplies a command named 'template' that works like the backtick but without the namespacing stuff.

In Clojure, quasiquotation and namespace resolution are mixed together in a single feature. This has great benefits for writing macros in a language like Clojure, which is a "Lisp-1" (as opposed to Common Lisp, which is a "Lisp-2", with separate namespaces for functions and variables.)

I also agree that it might have been better not to conflate these features, but it would have made the writing of macros in Clojure less elegant, so I can see why it works the way it does.