3

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")))))) 
yazz.com
  • 57,320
  • 66
  • 234
  • 385
  • I've used `eval` in such case. Just change ~x to ~(eval x). But I don't know, maybe there is another solution or you just misspelled with (= :type "special"). – m039 Jul 07 '11 at 19:43
  • When I use eval I get: (clojureql.core/select (clojureql.core/table oe.db.dbcore/db "users_table") (clojureql.core/where (clojure.core/eval quote (= :type "special")))) – yazz.com Jul 07 '11 at 19:57
  • 1
    It's really strange, for me `eval` is working (I tried (defmacro ss [x] `(* 3 ~(eval x))) (macroexpand '(ss '(+ 1 2)))). But if the code is expanded to (quote (= :type "special")) then I come to only one solution: to use ~(second x). But don't know why I don't like it. :) – m039 Jul 07 '11 at 20:26

2 Answers2

3

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.

mikera
  • 105,238
  • 25
  • 256
  • 415
  • I am using '(= :type "special") as it is passed around as a parameter in my program, as I cannot pass around (= :type "special") in Clojure without the ' – yazz.com Jul 07 '11 at 19:58
  • Hmmm not quite sure what you mean... are you trying to expand the macro at runtime using eval? if so you can run the command with (eval `(ss ~parameter)) – mikera Jul 07 '11 at 20:36
  • Zubair: `quote` quotes its entire argument. Have you tried mikera's suggestion? – Svante Jul 07 '11 at 20:43
  • Yes, that worked, thanks Mikera! I have updated the question to show what finally worked. – yazz.com Jul 08 '11 at 08:08
  • 1
    Why using `eval`, if `(cadr xx)` is sufficient (as long as the argument is always quoted)? – SK-logic Jul 08 '11 at 09:29
  • I never heard of cadr? Not much on the web about it either, do you have any good links to explain it? – yazz.com Jul 08 '11 at 11:44
2

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))))
kotarak
  • 17,099
  • 2
  • 49
  • 39