2012-07-23 34 views
6

为什么这一点的Clojure代码:Clojure的不断和地图功能

user=> (map (constantly (println "Loop it.")) (range 0 3)) 

产量输出:

Loop it. 
(nil nil nil) 

我希望它打印出“循环播放”三倍侧三次评估功能的效果。

回答

9

constantly不评估其参数多次。这是一个函数,而不是一个宏,因此在运行constantly之前,参数只被计算一次。所有constantly确实是需要的(评价)的说法,并返回每次被称为时间返回给定值的函数(无需重新评估什么,因为,正如我所说,constantly运行之前的说法已经被评估)。

如果您只想对该范围内的每个元素调用(println "Loop it"),则应该将其作为映射函数传递,以代替constantly。请注意,您实际上必须将其作为函数传递,而不是评估表达式。

+0

瞥源。这看起来像赢家。 – Mike 2012-07-23 13:10:45

+0

试图不断使用,以避免显式传递我不需要的参数。虽然会解决这个问题。 – Mike 2012-07-23 13:18:39

+10

请注意,如果你只是想副作用,你应该使用'doseq'或'dotimes'。由于'map'是懒惰的,除非你用'doall'或'dorun'强制执行,否则你不会得到你想要的结果。 – 2012-07-23 15:18:39

3

你可以通过USIG repeatedly和lambda表达式靠近你的意图的行为。

例如:

(repeatedly 3 #(println "Loop it")) 

除非你在REPL,这需要由一个dorun或类似的包围。 repeatedly是懒惰的。

+0

由于Lambda想要使用传递给它的参数,因此不会进行编译。在这种情况下,我宁愿忽略这个论点。 – Mike 2012-07-23 17:17:32

+0

我已经添加了一个使用示例,与您的类似。 – sortega 2012-07-23 20:42:38

+0

哦,这更有意义。谢谢! – Mike 2012-07-24 12:28:25

3

由于sepp2k正确地指出constantly是一个函数,所以它的参数将只计算一次。

惯用的方式来实现,你在这里做什么是使用doseq

(doseq [i (range 0 3)] 
    (println "Loop it.")) 

或可替代dotimes(因为你实际上并没有使用其在该特定情况下多了几分简洁高效)由range产生的序列:

(dotimes [i 3] 
    (println "Loop it.")) 

这些解决方案的两者都是非延迟,这可能是你想要什么,如果你是刚刚运行的副作用,一些代码。