2014-10-31 12 views
7

Eksperymentuję z makrami clojure i zastanawiałem się, co robię źle?makro clojure - nie wiem jak stworzyć ISeq od: clojure.lang.Symbol

Mam prosty przykład, próby dynamicznego tworzenia funkcji na podstawie mapy.

Na przykład:

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

Makro nie działa, ale wyjście debugowania wygląd jak powinno stworzyć właściwą strukturę:

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

Wszelkie porady będą bardzo mile widziane. Dzięki.

Odpowiedz

5

m-to-units jest makro, co oznacza, że ​​każdy parametr zostanie przekazany bez oceny, co oznacza, że ​​wewnątrz makra wartość units-map jest w rzeczywistości symbolem units.

Teraz, jeśli przejdą mapę bezpośrednio, to będzie działać zgodnie z przeznaczeniem:

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

(to-cm 10) 
;; => 1000 

Co można zrobić - wykorzystuje eval, aby uzyskać rzeczywistą wartość - chociaż ja to złą praktyką rozważyć mapy jednostek, bez względu na to, czy jest ona przekazywana jako mapa czy jako symbol:

(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 
Powiązane problemy