yazz.com
yazz.com

Reputation: 58786

How can I change a list to code in a Clojure macro?

I have the following macro:

(defmacro ss [x]

`(clojureql.core/select 
      (clojureql.core/table db "users_table")
      (clojureql.core/where  ~x)
  )
)

(macroexpand '(ss '(= :type "special")))

: but it produces :

(clojureql.core/select (clojureql.core/table oe.db.dbcore/db "users_table") (clojureql.core/where '(= :type "special"))) 

: instead of :

(clojureql.core/select (clojureql.core/table oe.db.dbcore/db "users_table") (clojureql.core/where (= :type "special"))) 

: I realise that the problem is I am passing in a list '(= :type "special"), but how can I get this to unquote in the macro?

Update:

I finally got this working thanks to Mikera's answer by doing this:

(defn ss [x]

  (clojureql.core/select 
      (clojureql.core/table db "users_table")
      x
  )


)

(macroexpand '(ss (eval `(clojureql.core/where ~'(= :type "special")))))

: although the output is slightly different it works as expected:

(ss (eval (clojure.core/seq (clojure.core/concat (clojure.core/list 'clojureql.core/where) (clojure.core/list '(= :type "special")))))) 

Upvotes: 3

Views: 165

Answers (2)

kotarak
kotarak

Reputation: 17299

You cannot pass runtime arguments to macros since the former are only known at - well - runtime, while the latter are already expanded and compiled at - well - compile time.

You must use a function.

(defn get-users-by-type
  [t]
  (cql/select
    (cql/table db "users_table")
    (cql/where (= :type t))))

Upvotes: 2

mikera
mikera

Reputation: 106351

Looks to me like you're passing the wrong thing to macroexpand: you should probably use:

(macroexpand '(ss (= :type "special")))

i.e. you ony need one quote at the beginning to quote the entire expression.

Upvotes: 3

Related Questions