对惰性序列的评估感到困惑
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 个项目的消息,而不是整个序列。
我正在试验 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 个项目的消息,而不是整个序列。