Clojure macro - don't know how to create ISeq from: clojure.lang.Symbol

I am experimenting with clojure macros and wonder what can I do wrong?

I have a simple example: try to dynamically create functions based on a map.

For example:

(def units {:cm 100 :mm 1000 :m 1 :km 1/1000}) (defn m-to-unit-helper [[kv]] (let [f (symbol (str "to-" (name k)))] `(defn ~f [m#] (* ~vm#)))) (defmacro m-to-units [units-map] (let [funcs (map m-to-unit-helper units-map)] `(do ~@funcs ))) ; complains with: Don't know how to create ISeq from: clojure.lang.Symbol (m-to-units units) ; To try and debug (defn debug [units-map] (let [funcs (map m-to-unit-helper units-map)] (clojure.pprint/pprint `(do ~@funcs )))) ; see below (debug units) 

The macro does not work, but the debug output looks like it should create the correct structure:

 (do (clojure.core/defn to-mm [m__32709__auto__] (clojure.core/* 1000 m__32709__auto__)) (clojure.core/defn to-m [m__32709__auto__] (clojure.core/* 1 m__32709__auto__)) (clojure.core/defn to-cm [m__32709__auto__] (clojure.core/* 100 m__32709__auto__)) (clojure.core/defn to-km [m__32709__auto__] (clojure.core/* 1/1000 m__32709__auto__))) 

Any advice would be greatly appreciated. Thanks.

+7
macros clojure
source share
1 answer

m-to-units is a macro that means that every parameter will be passed without evaluation, which means that inside the macro, the units-map value is actually a units symbol.

Now, if you transfer the card directly, it will work as intended:

  (m-to-units {:mm 1000, :m 1, :cm 100, :km 1/1000}) ;; => #'user/to-km (to-cm 10) ;; => 1000 

What you could do - although I thought it was bad practice - is used by eval to get the actual value of the map of units, regardless of whether it is passed as a map or through a symbol:

 (defmacro m-to-units [units-map] (let [funcs (map m-to-unit-helper (eval units-map))] `(do ~@funcs ))) (m-to-units units) ;; => #'user/to-km 
+5
source share

All Articles