2013-05-08 28 views
2

我已經想出了下面的函數,它按照預期工作,但是它使用了eval,這很可怕,並且在我打算使用它的ClojureScript中不存在。如何使用defmacro而不是eval?

(defn path [d p] 
    (eval 
    (concat '[-> d] 
     (flatten (map 
       #(conj (repeat (dec %) 'z/right) 'z/down) 
       (path-to-vector p)))))) 

如何將它轉換爲宏?我的嘗試是這樣的:

(defmacro path [d p] 
    `(concat (-> ~d) 
     (flatten 
     (map #(conj (repeat (dec %) z/right) z/down) 
      (path-to-vector ~p))))) 

但這顯然不起作用。

+0

首先,不需要在語法引用中使用concat。你的宏可能看起來像這樣:'( - > d〜@(flatten ...)) – Alex 2013-05-08 16:09:14

+0

你的宏將取決於它的用法,是編譯時可用的d和p值還是運行時的東西? – Ankur 2013-05-08 16:24:39

回答

4

無需宏或EVAL,操作只是一個reduce

(defn path [d p] 
    (reduce (fn [s v] 
      (reduce #(%2 %1) s (conj (repeat (dec v) z/right) z/down))) 
      d (path-to-vector p))) 

還要注意的是(conj (repeat (dec %) z/right) z/down)意味着Z /下來,然後所有的Z /右堂妹repeate返回一個序列,如果你想要所有z /右邊第一個和最後一個項目應該是z /向下,那麼你應該使用(conj (vec (repeat (dec %)) z/right) z/down)

1

Ankur是正確的,這是一個減少的情況,既不是一個宏或eval是合適的,雖然它可能仍然是值得解釋的機制編寫一個像這樣的宏,因爲它自己的原因:

您的宏的例子是非常密切的,你需要的是拼接,所享有的功能,使其工作:

(defmacro path [d p] 
    `(-> ~d 
     [email protected](flatten 
     (map #(conj (repeat (dec %) z/right) z/down) 
       (path-to-vector ~p))))) 

這個評估致電宏展開時壓平,然後將其連接成所產生的S-表達/列表。

+1

你不需要concat,只是'( - >〜d〜@(flatten ...)) – Ankur 2013-05-09 04:15:55

+0

這是真的:)我試圖保持儘可能接近原始。我會解決這個問題。 – 2013-05-09 17:52:51

相關問題