2014-10-31 6 views
7

Sto sperimentando con macro di clojure e mi sono chiesto cosa potrei fare di sbagliato?macro clojure - non so come creare ISeq da: clojure.lang.Symbol

Ho un semplice esempio di tentativo di creare dinamicamente funzioni basate su una mappa.

Ad esempio:

(def units {:cm 100 
      :mm 1000 
      :m 1 
      :km 1/1000}) 

(defn m-to-unit-helper [[k v]] 
    (let [f (symbol (str "to-" (name k)))] 
    `(defn ~f [m#] (* ~v m#)))) 

(defmacro m-to-units [units-map] 
    (let [funcs (map m-to-unit-helper units-map)] 
    `(do [email protected]))) 

; 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 [email protected])))) 

; see below 
(debug units) 

La macro non funziona, ma lo sguardo output di debug come dovrebbe creare la struttura corretta:

(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__))) 

Qualsiasi consiglio sarebbe molto apprezzato. Grazie.

risposta

5

m-to-units è una macro che significa che ogni parametro verrà passato senza essere valutato, nel senso che all'interno della macro il valore di units-map è in realtà il simbolo units.

Ora, se si passa direttamente alla mappa, che funzionerà come previsto:

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

(to-cm 10) 
;; => 1000 

cosa si potrebbe fare - anche se mi piacerebbe considero cattiva pratica - sta usando eval per ottenere il valore reale della mappa delle unità, indipendentemente dal fatto che sia passata come mappa o tramite un simbolo:

(defmacro m-to-units 
    [units-map] 
    (let [funcs (map m-to-unit-helper (eval units-map))] 
    `(do [email protected]))) 

(m-to-units units) 
;; => #'user/to-km