2016-03-09 70 views
0

我想編寫一個函數(REP-N-n次&參數),它應該像一個復讀功能:如何定義與宏

user=>(rep-n-times 3 (print "hello!") (print "bye")) 
hello! bye hello! bye hello! bye nil 

我的代碼是

(defmacro ntimes [n & body] 
     `(take ~n (repeat [email protected]))) 

測試:

#'user/rep-n-times 
user=> (rep-n-ntimes 5 (print "hah")) 
hah(nil nil nil nil nil) 
user=> (macroexpand '(rep-n-ntimes 4 (print "hello"))) 
(clojure.core/take 4 (clojure.core/repeat (print "hello"))) 

我該如何解決?

回答

3

在這種情況下,你正在做的事情的副作用,你應該使用doseqdotimes代替:

(dotimes [i 3] 
    (print "hello! bye ")) 

沒有必要定義REP-n次。如果您需要具有副作用的功能的結果,請使用repeatedly。還要注意,repeatedlyrepeat可選地將重複次數作爲參數。

(repeatedly 3 (fn [] (print "hello! bye ") (rand-int 10))) 

但是作爲與您的rep-n-times定義的問題,呼籲repeat只有一個參數,這是(print "hello")評估的結果是零。所以你要求4個零點,得到4個零點。打印發生一次,當參數評估爲零時。此外,它產生一個懶惰的序列,它恰好在REPL處進行評估,但這僅僅是因爲它正在被打印。您應該避免在懶惰序列中出現副作用(例如打印),因爲除非您明確瞭解序列,否則不會評估它們。

注意dotimes可以採取多種形式:

(dotimes [i 3] (print "h1") (print "h2") (print "h3")) 

這dotimes是一個宏定義here

您可以通過使用該代碼作爲起點寫你自己的版本:

(defmacro rep-n-times [n & body] 
    `(loop [i# ~n] 
    (when (pos? i#) 
     [email protected] 
     (recur (dec i#))))) 
+0

嗨蒂莫西!我完全同意你的看法!但是,我很抱歉,我沒有明確提出問題。我被要求編寫一個必須用宏定義的函數,而且我不會重複相同的字符串。正如我上面的問題,該函數需要一個或兩個或更多的參數。像(代表5次(打印「你好」)(打印「良好」)(打印「夜」)....)。 –

+0

Hi Xiufen,好的,我添加了一個如何實現它作爲宏的答案的例子。 –

+0

嗨蒂莫西!我真的很感激。我查了很多關於auto-gensym和gensym的材料,但我仍然不知道這些材料究竟是做什麼的。這意味着什麼「使用gensym獲得唯一標識符」?謝謝 –