假設我們有一個在任意位置有_
的列表。例如:(a b c _ e f)
。我試圖編寫一個宏,對於這樣的列表,找到_
並用另一個值(例如,z
)替換它:(a b c z e f)
。寫入替換宏的參數
這是最好的方法是什麼?
假設我們有一個在任意位置有_
的列表。例如:(a b c _ e f)
。我試圖編寫一個宏,對於這樣的列表,找到_
並用另一個值(例如,z
)替換它:(a b c z e f)
。寫入替換宏的參數
這是最好的方法是什麼?
你確定你需要一個宏嗎?使用replace應該只要你引用列表中很好地工作:
(replace '{_ z} '(a b c _ e f)) ; => (a b c z e f)
的@Josh答案是正確的,首先你要決定你是否真的需要宏觀的東西。我可以想象一個合成的例子。讓我們假設你要定義一個函數,但需要跟蹤一些原因,這_
值(也許登錄),使用它是這樣的:
(defn-with-placeholder my-fn [a b c _ e] z
(println a b c z e))
這是你如何做到這一點:
(defmacro defn-with-placeholder [name args placeholder & body]
`(defn ~name ~(vec (replace {'_ placeholder} args))
[email protected]))
請注意,我使用了前面提出的相同的replace
方法。
測試一下在REPL:
user> (defn-with-placeholder my-fn [a b _ d] placeholder
(println a b placeholder d))
#'user/my-fn
user> (my-fn 1 2 3 4)
1 2 3 4
nil
確定現在是好看不中用。讓我們與運動走得更遠,並進行了定義,將收集所有省略的參數一些集合(如函數休息參數& args
,但在不同的位置) 因此,我們可以定義一個宏defn-with-omitted
認爲是這樣的:
(defn-with-omitted my-fn-2 [a _ c _ e f _ h] other-args
(println :parameters a c e f h)
(println :other-parameters other-args))
在REPL:
user> (my-fn-2 1 100 2 200 3 4 300 5)
:parameters 1 2 3 4 5
:other-parameters {1 100, 3 200, 6 300}
nil
其收集的所有數據省略和它把至other-args
地圖,用Arg-位置ARG映射。
要做到這一點,首先,我們需要建立一個處理的arglist並收集所有被省略參數的函數:
(defn process-args [args]
(reduce-kv (fn [[args omitted] idx arg]
(if (= '_ arg)
(let [sym-name (gensym "omitted")]
[(conj args sym-name)
(assoc omitted idx sym-name)])
[(conj args arg) omitted]))
[[] {}]
args))
這裏就是它的作用:
user> (process-args '[a _ b c _ _ f g])
[[a omitted29608 b c omitted29609 omitted29610 f g]
{1 omitted29608, 4 omitted29609, 5 omitted29610}]
注意到我在這裏使用gensym
,不是爲了隱藏可能的外部定義。
所以現在它很容易使宏:
(defmacro defn-with-omitted [name args omitted-name & body]
(let [[args omitted] (process-args args)]
`(defn ~name ~args
(let [~omitted-name ~omitted]
[email protected]))))
讓我們檢查的擴展:
(defn-with-omitted my-fn-2 [a _ c _ e f _ h] other-args
(println :parameters a c e f h)
(println :other-parameters other-args))
擴展爲:
(defn my-fn-2 [a omitted29623 c omitted29624 e f omitted29625 h]
(let [other-args {1 omitted29623, 3 omitted29624, 6 omitted29625}]
(println :parameters a c e f h)
(println :other-parameters other-args)))
這正是我們想要的東西。
這是優雅的,但我誤解了我的問題:我需要的不是要返回列表,而是要替換,然後評估。在沒有'eval'的ClojureScript中,如何實現這一點? – George