2017-01-12 17 views
0

destrucutred引数を使用するマクロを書くときに問題があります。次に例を示します。ここではマクロを使用して構造化されたargsを渡す

(defmacro defny 
    [n args & forms] 
    `(defn ~n ~args [email protected])) 

(defmacro defnz 
    [n f args & forms] 
    `(defn ~n ~args 
    (do 
     (~f [email protected]) 
     [email protected]))) 

(defny y 
    [{:keys [value] :as args}] 
    (println "Y ARGS" args) 
    (println "Y VALUE" value)) 

(defnz z y 
    [{:keys [value] :as args}] 
    (println "Z ARGS" args) 
    (println "Z VALUE" value)) 

、私は同じことをしている、二つのマクロ、単にDEFNして呼び出してdefny、およびdefnzを持っているが、さらにdefnzの引数に先立ち、関数本体に呼び出す別の関数を受け入れます。

Iは、z起動すると、私は両方の値と引数が同じプリントアウト見ることを期待し、その代わりに、私は得る:

(z {:value 1}) 
Y ARGS {:keys [1], :as {:value 1}} 
Y VALUE nil 
Z ARGS {:value 1} 
Z VALUE 1 
=> nil 

これが起こっている理由私が見ることができ、破壊さ引数{:キー[1 ]:as {:value 1}}がyに渡されていますが、defnzマクロを修正して、構造化されたargsを適切に渡せるようにする方法がわかりません。

あなたが簡単にマクロ展開で間違いを見ることができます
+0

は 'macroexpand'と' macroexpandは-1 'あなたのマクロが生産しているどのようなコードを参照することをお試しください。 –

答えて

2

:あなたが正しいです

(defn z [{:keys [value], :as args}] 
    (do 
    (y [{:keys [value], :as args}]) 
    (println "Z ARGS" args) 
    (println "Z VALUE" value))) 

(defnz z y 
    [{:keys [value] :as args}] 
    (println "Z ARGS" args) 
    (println "Z VALUE" value)) 

はに展開あなたは全体の引数を渡すyに形成するが、何を必要とすることを作るています行を(y args)に展開します。ここで、argsは単なるシンボルです。

(defmacro defnz 
    [n f args & forms] 
    `(defn ~n ~args 
    (do 
     (~f ~'args) 
     [email protected]))) 

は今拡大が正しいだろう:あなたは「引用にunquote」トリック使用する必要があります(記号なし名前空間で修飾するものをオンする)マクロの中でそれを行うには

(defn z [{:keys [value], :as args}] 
    (do (y args) (println "Z ARGS" args) (println "Z VALUE" value))) 

を、それはかなり悪いです{:keys [value]:all-of-them}のようにdefnzに渡されるallargsの名前を正確には知らないので(defnzはそれがargsであると予想しています)、動的に修正することができますdefnzのallargsの名前を取得する:

(defmacro defnz 
    [n f [a :as args] & forms] 
    (let [a (if (:as a) a (assoc a :as 'everything))] 
    `(defn ~n ~[a] 
     (do 
     (~f ~(:as a)) 
     [email protected])))) 

ので、今、それは次のように展開します:

(defnz z y 
    [{:keys [value] :as args}] 
    (println "Z ARGS" args) 
    (println "Z VALUE" value)) 

;;(defn z [{:keys [value], :as args}] 
;; (do (y args) (println "Z ARGS" args) (println "Z VALUE" value))) 


(defnz z y 
    [{:keys [value] :as all-args}] 
    (println "Z ARGS" all-args) 
    (println "Z VALUE" value)) 

;;(defn z [{:keys [value], :as all-args}] 
;; (do 
;; (y all-args) 
;; (println "Z ARGS" all-args) 
;; (println "Z VALUE" value))) 

(defnz z y 
    [{:keys [value]}] 
    (println "Z ARGS" everything) 
    (println "Z VALUE" value)) 

;;(defn z [{:keys [value], :as everything}] 
;; (do 
;; (y everything) 
;; (println "Z ARGS" everything) 
;; (println "Z VALUE" value))) 
関連する問題