2016-03-09 41 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获得唯一标识符”?谢谢 –