2013-05-09 1 views
1

Я новичок Clojure, используя Light Table, чтобы узнать макросы. Моя цель - преобразовать вектор карт в список инструкций def.Как вы преобразуете вектор карт в ряд символов, которые соответствуют определенной карте?

Я хочу, чтобы преобразовать следующую структуру данных:

(def label-data 
    [ 
    {:label "lbl_first"} 
    {:label "lbl_second"} 
    {:label "lbl_third"} 
    {:label "lbl_fourth"} 
    ] 
) 

... в следующих четкости утверждений:

(def L1 {:label "lbl_first"}) 
    (def L2 {:label "lbl_second"}) 
    (def L3 {:label "lbl_third"}) 
    (def L4 {:label "lbl_fourth"}) 

Я знаю, как создать макрос, который генерирует один четкости заявление:

(defmacro def-label [num] 
    (let [ idx (dec num) 
     symb (symbol (str "L" idx)) 
     datum (label-data num) 
     syntax `(def ~symb ~datum)] 
    syntax)) 

Когда я использую макрос ...

(def-label 2) 

я могу увидеть символ, генерируемый макрос успешно решает ...

L2 

Теперь я могу осмыслять создать макрос, который выглядит следующим образом:

(defmacro generate-def-statements-from [lbldata] 

) 

но я я не понимаю, как выполнить итерацию над макросом def-label 4 раза, чтобы сгенерировать требуемые несколько инструкций def. Может ли кто-нибудь показать мне лучшую технику для достижения этой цели?

Благодарим вас за советы и рекомендации, заранее.

ответ

1

Макросы

  1. Не оценивать их аргументы
  2. ли оценить их возвращаемое значение

Так,

(defmacro generate-def-statements-from [lbldata] 
    `(do [email protected](map-indexed 
      (fn [idx itm] `(def ~(symbol (str "L" (inc idx))) ~itm)) 
      lbldata))) 

бы работать над буквальным выражением

(macroexpand 
    '(generate-def-statements-from 
    [ {:label "lbl_first"} 
     {:label "lbl_second"} 
     {:label "lbl_third"} 
     {:label "lbl_fourth"} ])) 

;=> (do 
;  (def L1 {:label "lbl_first"}) 
;  (def L2 {:label "lbl_second"}) 
;  (def L3 {:label "lbl_third"}) 
;  (def L4 {:label "lbl_fourth"})) 

и оценил бы форму do на def на этикетках.

2

Макросы превращают одно выражение в другое выражение, поэтому вам нужно создать одно выражение. Это может быть достигнуто путем обертывания def сек в do

user> (defmacro def-label-data [label-data] 
      `(do [email protected](map #(list 'def %1 %2) 
         (map #(symbol (str "L" %)) 
            (range 1 (inc (count label-data)))) 
         label-data))) 
#'user/def-label-data 

user> (macroexpand '(def-label-data [{:label "lbl_first"} 
            {:label "lbl_second"} 
            {:label "lbl_third"} 
            {:label "lbl_fourth"}])) 
(do (def L1 {:label "lbl_first"}) 
    (def L2 {:label "lbl_second"}) 
    (def L3 {:label "lbl_third"}) 
    (def L4 {:label "lbl_fourth"})) 

Это не может быть intuative исходя из многих других языков, где определения новых форм верхнего уровня может произойти только на верхнем уровне. В clojure это не так. Вы можете вызывать def на любом уровне, даже в другой форме. Просто помните, что это производит верхний уровень var.

Если вы хотите сделать это как функцию вместо макроса, то вы не можете использовать def, потому что это специальная форма, которая рассматривает это первый аргумент как символ без его оценки.удача intern делает то же самое, что и def, за исключением того, что оценивает его аргументы:

user> (defn def-label-data [label-data] 
     (map #(intern *ns* %1 %2) 
       (map #(symbol (str "L" %)) 
        (range 1 (inc (count label-data)))) 
       label-data)) 
#'user/def-label-data 

user> (def-label-data [{:label "lbl_first"} 
         {:label "lbl_second"} 
         {:label "lbl_third"} 
         {:label "lbl_fourth"} 
         {:label "lbl_fifth"}]) 
(#'user/L1 #'user/L2 #'user/L3 #'user/L4 #'user/L5) 
user> L5 
{:label "lbl_fifth"} 
user> L4 
{:label "lbl_fourth"} 
user> L3 
{:label "lbl_third"} 
user> L2 
{:label "lbl_second"} 
user> L1 
{:label "lbl_first"} 

 Смежные вопросы

  • Нет связанных вопросов^_^