(println(iterate inc 0)):为什么这甚至开始打印?

时间:2015-05-17 09:10:15

标签: clojure lazy-sequences

当我在我的repl中运行(println (iterate inc 0))时,我会得到这样的结果:

user=> (println (iterate inc 0))
(0 1 2 3 4 5 6 7 8 9 10 11 12 13 ....................

我运行代码时的期望是repl没有显示任何内容而只是因为(iterate inc 0)永远不会结束而卡住了。但是,我看到(0 1 2 3 ...

(iterate inc 0)生成永不返回的无限序列。如果它永远不会结束,那么为什么println开始打印值?

换句话说,即使输入从未完成评估,为什么(println xx)开始被评估?

2 个答案:

答案 0 :(得分:8)

你应该在Clojure上阅读lazy seqs。他们能够产生在实现整个序列之前可以逐步消耗的值(在这种情况下,永远不会发生)。

将其视为推拉与拉动可能会有所帮助。而不是迭代创建一个完整的值列表然后将它们推送到println函数(这将永远不会发生),迭代只是将它交给一个懒惰的序列,println根据需要拉取值。这就是为什么(取5(iterate inc 0))有效;在停止之前,只尝试拉出5个值。

答案 1 :(得分:2)

Clojure的打印比System.out.println更聪明;它可以是customized for different types。在序列的情况下,walks through element-by-element, printing each one as it goes - 我们不必等到评估整个序列才开始打印。

相比之下,在打印前调用System.out.println的{​​{1}}的行为更像您的预期。它永远挂起,不打印任何东西,因为toString需要评估整个序列 - 或者,至少,如果它没有尝试构建字符串的内存不足,它将永远挂起。

那就是说,整个表达确实被卡住了 - 如果你等着它停止打印,你就永远等待:

toString