【发布时间】:2012-07-24 21:10:55
【问题描述】:
为什么会有这段 Clojure 代码:
user=> (map (constantly (println "Loop it.")) (range 0 3))
产生这个输出:
Loop it.
(nil nil nil)
我希望它会打印 3 次“循环它”作为对函数进行 3 次评估的副作用。
【问题讨论】:
标签: clojure functional-programming
为什么会有这段 Clojure 代码:
user=> (map (constantly (println "Loop it.")) (range 0 3))
产生这个输出:
Loop it.
(nil nil nil)
我希望它会打印 3 次“循环它”作为对函数进行 3 次评估的副作用。
【问题讨论】:
标签: clojure functional-programming
constantly 不会多次评估其参数。它是一个函数,而不是宏,因此在 constantly 运行之前,该参数只被评估一次。 constantly 所做的只是它接受其(评估的)参数并返回一个函数,该函数在每次调用它时都返回给定的值(无需重新评估任何东西,因为正如我所说,在 constantly 甚至运行之前已经评估了参数) .
如果您只想为范围内的每个元素调用(println "Loop it"),则应将其作为要映射的函数传入,而不是constantly。请注意,您实际上必须将其作为函数传递,而不是计算表达式。
【讨论】:
doseq 或dotimes。由于map 是惰性的,除非你用doall 或dorun 强制它,否则你不会得到你想要的结果。
constantly 的描述有误。你描述repeat。 constantly 返回一个函数,调用该函数时将返回提供给 constantly 的值。
正如 sepp2k 正确指出的那样,constantly 是一个函数,所以它的参数只会被计算一次。
实现您在这里所做的惯用方法是使用doseq:
(doseq [i (range 0 3)]
(println "Loop it."))
或者dotimes(在这种特殊情况下更简洁有效,因为您实际上并没有使用range产生的序列):
(dotimes [i 3]
(println "Loop it."))
这两种解决方案都是非惰性的,如果您只是为副作用运行一些代码,这可能是您想要的。
【讨论】:
您可以通过使用 repeatedly 和 lambda 表达式获得接近您意图的行为。
例如:
(repeatedly 3 #(println "Loop it"))
除非您在 REPL,否则它需要被 dorun 或类似名称包围。 repeatedly 很懒。
【讨论】: