【问题标题】:Clojure. Why the wrapper lazy-seq is required?克洛朱尔。为什么需要包装惰性序列?
【发布时间】:2019-04-08 16:44:27
【问题描述】:

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

【问题讨论】:

标签: clojure


【解决方案1】:

第一个是懒惰的。它只根据需要评估序列的元素。然而,第二个是严格的,并且会立即完成整个序列。如果您在每个中添加一些 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。如果您认为您可能不需要整个序列,或者序列是无限的,或者您想使用 mapfilter 对多个转换进行排序,则首选惰性解决方案。如果您可能在某个时候需要整个序列和/或您需要快速随机访问,请使用严格的解决方案。

【讨论】:

    猜你喜欢
    • 2014-06-06
    • 2018-10-15
    • 1970-01-01
    • 2018-01-13
    • 1970-01-01
    • 1970-01-01
    • 2011-10-21
    • 2011-01-09
    • 2014-06-25
    相关资源
    最近更新 更多