对惰性序列的评估感到困惑

Confused about evaluation of lazy sequences

我正在试验 clojure 的惰性序列。为了查看项目的评估何时发生,我创建了一个名为 square 的函数,它在返回结果之前打印结果。然后我使用 map 将此函数应用于矢量。

(defn square [x]
  (let [result (*  x x)]
  (println "printing " result)
  result))

(def s (map square [1 2 3 4 5])) ; outputs nothing

在我的 s 声明中,REPL 没有输出任何内容。这表示计算尚未开始。这似乎是正确的。然后我做:

(first s)

函数“first”只接受第一项。所以我希望只有 1 个会被评估。我的期望是 REPL 将输出以下内容:

printing 1
1

然而,REPL 却输出了以下内容。

printing 1
printing 4
printing 9
printing 16
printing 25
1

所以它不是只评估第一个项目,而是评估所有项目,即使我只访问第一个项目。

如果一个lazy sequence的状态只能是所有值计算和没有值计算,那么它如何获得lazy evaluation的优势呢?我来自方案背景,我期待更像流的行为。看来我错了。谁能解释一下这是怎么回事?

懒惰不是全有或全无,但 seq 的某些实现对输入序列的 'chunks' 进行操作(有关解释,请参阅 here)。这是 vector 的情况,您可以使用 chunked-seq?:

进行测试
(chunked-seq? (seq [1 2 3 4 5]))

当给定一个集合时 map checks to see 如果基础序列被分块,并且如果是这样,则逐块计算结果而不是一次计算一个元素。

块大小通常为 32,因此您可以通过比较

的结果看到此行为
(first (map square (vec (range 35))))

这应该只显示前 32 个项目的消息,而不是整个序列。