为什么需要包装lazy-cons?有两个函数的结果相同。
(defn seq1 [s]
(lazy-seq
(when-let [x (seq s)]
(cons (first x) (seq1 (rest x))))))
(defn seq2 [s]
(when-let [x (seq s)]
(cons (first x) (seq2 (rest x)))))
两种情况下我得到的结果都是相同的,没有分块的序列。
repl.core=> (first (map println (seq1 (range 1000))))
0
nil
repl.core=> (first (map println (seq2 (range 1000))))
0
nil
repl.core=> (chunked-seq? (seq2 (range 1000)))
false
repl.core=> (chunked-seq? (seq1 (range 1000)))
false
答案 0 :(得分:2)
第一个是懒惰。它仅根据需要评估序列的元素。但是第二个是严格的,并立即遍历整个序列。如果您在每个通话中添加一些println
通话,则可以看到这一点:
(defn seq1 [s]
(lazy-seq
(when-let [x (seq s)]
(println "Seq1" (first x))
(cons (first x) (seq1 (rest x))))))
(defn seq2 [s]
(when-let [x (seq s)]
(println "Seq2" (first x))
(cons (first x) (seq2 (rest x)))))
(->> (range 10)
(seq1)
(take 5))
Seq1 0
Seq1 1
Seq1 2
Seq1 3
Seq1 4 ; Only iterated over what was asked for
=> (0 1 2 3 4)
(->> (range 10)
(seq2)
(take 5))
Seq2 0
Seq2 1
Seq2 2
Seq2 3
Seq2 4
Seq2 5
Seq2 6
Seq2 7
Seq2 8
Seq2 9 ; Iterated over everything immediately
=> (0 1 2 3 4)
因此,要回答这个问题,仅当您打算仅根据需要进行序列的迭代时,才需要lazy-seq
。如果您认为您不需要整个序列,或者该序列是无限的,或者您想使用map
或filter
对多个转换进行排序,则最好使用惰性解决方案。如果您可能在某个时候需要整个序列和/或需要快速随机访问,请使用严格的解决方案。