我正在尝试在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次。为什么不呢?
答案 0 :(得分:12)
你需要注意的最重要的事情是,Clojure中的序列是懒惰的。这意味着序列中的项目仅在需要时进行评估。这允许您使用无限序列。
大多数情况下,这就是你想要的,但是当你对序列项的值不感兴趣时,可能会让人感到困惑,但是在创建序列项的函数的副作用中。在您的示例中,序列由println
函数的100个返回值组成,即nil
的100倍 - 不是很有趣。但是println
函数具有将“Hello World”打印到stdout的副作用。
问题是,如果您从未对序列中的项目执行任何操作,则永远不会评估println
函数,也不会打印字符串。它在REPL中有效,因为REP中的P代表打印 - 打印您输入的表达式的返回值。要打印整个序列,必须对其进行评估,因此您会看到一堆“Hello World”,但也会看到一堆nils
。如果你在REPL之外运行代码(不使用返回的值),你将看不到Hello Worlds。
如果您对商品生成功能的副作用感兴趣,可以使用doall
或doseq
。 doall
强制评估整个序列并将其返回:
(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}}