1

为什么需要包装器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
4

1 回答 1

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只有当您打算仅根据需要进行序列迭代时才需要。如果您认为您可能不需要整个序列,或者序列是无限的,或者您想使用mapor对多个转换进行排序,则首选惰性解决方案filter。如果您可能在某个时候需要整个序列和/或您需要快速随机访问,请使用严格的解决方案。

于 2019-04-08T16:52:41.147 回答