2016-09-27 47 views
1

我試圖編寫一個宏來比較多個表達式的運行時間,並將其運行到牆上。我的問題可以濃縮爲下面的代碼:使用可變參數宏作爲列表

(defmacro test-m [& exprs] 
    `(map #(.toString %) ~exprs)) 

如果我把這種喜歡(test-m 1 2 3),我希望它可以沿着線生產代碼:

(map #(.toString %) [1 2 3]) 

這是完全有效的。但不幸的是,這實際上導致一個錯誤:

ClassCastException java.lang.Long cannot be cast to clojure.lang.IFn helpers.general-helpers/eval663 (NO_SOURCE_FILE:76)

的唯一途徑,我可以看到這個可能發生的事情是,如果& exprs導致(1 2 3),那麼這將嘗試調用1的功能,這顯然是錯誤的。

如何映射宏中的可變參數列表?

回答

3

我在寫這個問題的時候想到了它,所以我想我會發佈一個答案,以防其他人在未來陷入困境。

參數列表需要首先強制進入列表表達式,否則它將被評估爲表單。這是可以做到這樣的:

(defmacro test-m [& exprs] 
    `(map #(.toString %) (list [email protected])) 

注意exprs通過@擴大,並給予list。 (感謝@amalloy糾正)。

明顯是回顧,但它讓我暫時停留了一段時間。希望這有助於某人。

+0

你可能不想引用它,而是寫'(list〜@ exprs)'或'〜(vec exprs)'。 – amalloy

+0

@amalloy最後有什麼不同?引用它似乎更直接。我並不想爭辯;我很好奇。 – Carcigenicate

+0

用x y z變量而不是1 2 3個常量嘗試。 – amalloy