tungsten
tungsten

Reputation: 328

Clojure: Error in macro. "No such var"

I have a problem when I'm using macros in clojure. Here is what I'm trying to do.

(defmacro working-example []
  '(+ foo 1))

(defn working-function [foo]
  (working-example))

(working-function 2) ; => 3

(defmacro broken-example [bar]
  `(+ foo ~bar))

(defn broken-function [foo]
  (broken-example 1)) ; => I get error here.

(broken-function 2) ; Should be 3.

I want the broken-example macro to only replace text just like working-example does. Why doesn't it work and how should do I get it to work?

Upvotes: 2

Views: 747

Answers (1)

Diego Sevilla
Diego Sevilla

Reputation: 29021

I'm fairly new to Clojure, but I'll try to explain you what's happening here. Quoting and backquoting are different in how they treat symbols. For example, you can write similar code that result in subtle differences:

user=> '(+ foo 2)
(+ foo 2)
user=> `(+ foo 2)
(clojure.core/+ user/foo 2)

Note how just using backquote "binds" the symbols to the corresponding namespace (clojure.core for + and user for foo). In the contrary, quoting just treats the symbol as-is. If you want to correctly write your broken function, you can use the list syntax:

(defmacro broken-example [bar]
  (list '+ 'foo bar))

(defn broken-function [foo]
  (broken-example 1))

(broken-function 2)

Now broken-function outputs the expected result.

EDIT:

Now thanks to A. Webb comment below, you can also avoid the namespace binding by using this syntax:

(defmacro broken-example [bar]
  `(+ ~'foo ~bar))

Upvotes: 5

Related Questions