为什么我的代码打印不应该像它应该的那样?

时间:2011-09-07 22:16:18

标签: clojure for-loop

我正在尝试在Clojure中创建一个for。

我正在关注the cheats sheet from the Clojure site

e.g:

(take 100 (for [x (range 100000000) y (range 1000000) :while (< y x)] [x y]))

我正在尝试创建自己的for,它应该打印“Hello World”100次。

(take 100 (for [a (range 100) 
      :while (< a 100)] 
    (println "Hello World")
    )
)

出于某种原因,它不会打印Hello World 100次。为什么不呢?

3 个答案:

答案 0 :(得分:12)

你需要注意的最重要的事情是,Clojure中的序列是懒惰的。这意味着序列中的项目仅在需要时进行评估。这允许您使用无限序列。

大多数情况下,这就是你想要的,但是当你对序列项的值不感兴趣时​​,可能会让人感到困惑,但是在创建序列项的函数的副作用中。在您的示例中,序列由println函数的100个返回值组成,即nil的100倍 - 不是很有趣。但是println函数具有将“Hello World”打印到stdout的副作用。

问题是,如果您从未对序列中的项目执行任何操作,则永远不会评估println函数,也不会打印字符串。它在REPL中有效,因为REP中的P代表打印 - 打印您输入的表达式的返回值。要打印整个序列,必须对其进行评估,因此您会看到一堆“Hello World”,但也会看到一堆nils。如果你在REPL之外运行代码(不使用返回的值),你将看不到Hello Worlds。

如果您对商品生成功能的副作用感兴趣,可以使用doalldoseqdoall强制评估整个序列并将其返回:

(doall (for [a (range 100)] (println "Hello World")))

doseq不返回序列(它返回nil)并且语法类似for

(doseq [a (range 100)] (println "Hello World"))

另请注意,您实际上只需提供一次所需的计数(100)。 range函数已生成一个包含100个项目的序列。代码中的:while子句是多余的,take函数也是如此(从包含100个项目的序列中获取前100个项目并不多)。

希望这有帮助!

答案 1 :(得分:2)

尝试在前面添加 doall for 函数创建一个延迟序列, take 也是如此。在您添加 doall 之前,他们可能无法评估。

这个小怪癖在Clojure中是一个常见的烦恼,但是一旦你对“懒惰地思考”感到更加自在,这就有意义了。

答案 2 :(得分:1)

实际上,它对我有用。最后一个示例 打印一百"Hello World",但take只获得一百nil个也在REPL中打印的 user=> (take 100 (for [x (range 100000000) y (range 1000000) :while (< y x)] [x y])) ([1 0] [2 0] [2 1] [3 0] [3 1] [3 2] [4 0] [4 1] [4 2] [4 3] [5 0] [5 1] [5 2] [5 3] [5 4] [6 0] [6 1] [6 2] [6 3] [6 4] [6 5] [7 0] [7 1] [7 2] [7 3] [7 4] [7 5] [7 6] [8 0] [8 1] [8 2] [8 3] [8 4] [8 5] [8 6] [8 7] [9 0] [9 1] [9 2] [9 3] [9 4] [9 5] [9 6] [9 7] [9 8] [10 0] [10 1] [10 2] [10 3] [10 4] [10 5] [10 6] [10 7] [10 8] [10 9] [11 0] [11 1] [11 2] [11 3] [11 4] [11 5] [11 6] [11 7] [11 8] [11 9] [11 10] [12 0] [12 1] [12 2] [12 3] [12 4] [12 5] [12 6] [12 7] [12 8] [12 9] [12 10] [12 11] [13 0] [13 1] [13 2] [13 3] [13 4] [13 5] [13 6] [13 7] [13 8] [13 9] [13 10] [13 11] [13 12] [14 0] [14 1] [14 2] [14 3] [14 4] [14 5] [14 6] [14 7] [14 8]) 。第一个示例按原样运行:

(dotimes [i 100] (println "Hello World"))

对于实际打印,您可以尝试更简单的循环:

for

最后,如果您使用:while,则不需要(take 100 (for [a (range 100)] (println "Hello World"))) ,因为该范围已有100个元素:

{{1}}