1
votes

I want to create a macro so that i can add the variable name inside the variable itself. I have this Unit record. Its name member stores the name of variable that would have been created. i.e. like (def a-variable (->Unit 1 1 "a-varible")) but i donot want to pass the variable name myself.

And i think macros can come handy. :)

Here is the code :

(defrecord Unit 
    [value gradient name]
  Object
  (toString [_]
    (str name " : ")))


(defmacro create-unit1 [var-name & body]
  `(def ~var-name ~(concat body (list (name var-name)))))

(defmacro create-unit2 [var-name & body]
  `(def ~var-name (concat ~@body (list (name '~var-name)))))

But none of them is giving me write code :

neurals.core> (macroexpand '(create-unit1 a (->Unit 1.0 0.0)))
(def a ((->Unit 1.0 0.0) "a"))

neurals.core> (macroexpand '(create-unit2 a (->Unit 1.0 0.0)))
(def a (clojure.core/concat 
       (->Unit 1.0 0.0) (clojure.core/list 
                           (clojure.core/name (quote a)))))
neurals.core> 

I wanted :

(def a (->Unit 1.0 0.0 (clojure.core/name (quote a))))

What is the right way to execute the concat inside the macro ?

1

1 Answers

2
votes

You can fix your code by removing the & in create-unit1:

(defmacro create-unit1 [var-name body]
  `(def ~var-name ~(concat body (list (name var-name)))))

(macroexpand `(create-unit1 a (->Unit 1.0 1.0)))
;; => (def user/a (user/->Unit 1.0 1.0 "a"))

You could also add a little bit of syntactic sugar:

(defmacro create-unit1 [var-name body]
  `(def ~var-name (~@body ~(name var-name))))

Or, to keep all of that more idiomatic:

(defmacro defunit [sym value gradient]
  `(def ~sym (->Unit ~value ~gradient ~(name sym))))

(defunit a 1.0 1.0)
;; => #user.Unit{:value 1.0, :gradient 1.0, :name "a"}