1

私はマクロを学ぶために Light Table を使用する Clojure の初心者です。私の目標は、マップのベクトルを def ステートメントのリストに変換することです。

次のデータ構造を変換したい:

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

...次の def ステートメントに:

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

単一の def ステートメントを生成するマクロを作成する方法を知っています。

(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 ステートメントを生成するために def-label マクロを 4 回反復する方法を理解していません。誰かがこの目的を達成するための最良のテクニックを教えてもらえますか?

事前にアドバイスとご指導をよろしくお願いいたします。

4

2 に答える 2

2

マクロは 1 つの式を別の式に変換するため、 1 つの式を作成する必要があります。これは、defs をdo

user> (defmacro def-label-data [label-data]
          `(do ~@(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"}))

これは、新しいトップ レベル フォームの定義がトップ レベルでしかできない他の多くの言語から来ているため、直感的ではないかもしれません。clojure ではそうではありません。別の形式であっても、任意のレベルで def を呼び出すことができます。トップレベルの変数を生成することを覚えておいてください。

これをマクロではなく関数として実行したい場合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"} 
于 2013-05-09T21:48:31.073 に答える
1

マクロ

  1. 彼らの議論を評価しないでください
  2. 戻り値を評価する

そう、

 (defmacro generate-def-statements-from [lbldata] 
  `(do ~@(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てラベルを作成します。

于 2013-05-09T21:43:05.150 に答える