Search code examples
vectorclojurehashmapmacros

Clojure : Passing values of variable to macros


I want to convert {a 1, b 2} clojure.lang.PersistentArrayMap into [a 1 b 2] clojure.lang.PersistentVector in clojure.

I have tried to write a function in clojure which converts {a 1, b 2} into [a 1 b 2]. I have also written a macro which gives me expected end result. In clojure we cannot pass the values generated inside functions to macros. For that I wanted to know a way in which I can implement a macro directly which can convert {a 1, b 2} into (let [a 1 b 2] (println a)), which will return 1.

Dummy Macro:

(defmacro mymacro [binding & body]
--some implemetation---)

Execution :

(mymacro '{a 1, b 2} (println a))

output:

1
nil

My Implementaion:

Function which converts into desired output.

(defn myfn [x]
 (let [a (into (vector) x) b (vec (mapcat vec a))]  b))

Execution:

(myfn '{a 1, b 2})

Output:

[a 1 b 2]

MACRO:

(defmacro list-let [bindings & body] `(let ~(vec bindings) ~@body))

Execution:

(list-let [a 1 b 2] (println a))

Output:

1
nil

I wanted to know how can I implement the same inside the macro itself and avoid the function implementation to get the require output. Something same as dummy macro given above. I am also interested in knowing if there is any which through which I can pass the value from my funtion to the macro without using (def)


Solution

  • in general, macro code is plain clojure code (with the difference that it returns clojure code to be evaluated later). So, almost anything you can think of coding in clojure, you can do inside macro to the arguments passed.

    for example, here is the thing you're trying to do (if i understood you correctly):

    (defmacro map-let [binding-map & body]
      (let [b-vec (reduce into [] binding-map)]
        `(let ~b-vec ~@body)))
    
    (map-let {a 10 b 20} 
      (println a b) 
      (+ a b))
    ;;=> 10 20
    30
    

    or like this:

    (defmacro map-let [binding-map & body]
      `(let ~(reduce into [] binding-map) ~@body))
    

    or even like this:

    (defmacro map-let [binding-map & body]
      `(let [~@(apply concat binding-map)] ~@body))