clojure Lazness:防止不必要的mapcat结果实现

clojure Lazness:防止不必要的mapcat结果实现,clojure,lazy-evaluation,Clojure,Lazy Evaluation,考虑一个查询函数q,它返回一些(比如说十个)延迟结果 延迟功能: (defn dlay [x] (do (Thread/sleep 1500) x)) (defn q [pg] (lazy-seq (let [a [0 1 2 3 4 5 6 7 8 9 ]] (println "q") (map #(+ (* pg 10) %) (dlay a))))) 查询功能: (defn dlay [x] (do (Thread/slee

考虑一个查询函数q,它返回一些(比如说十个)延迟结果

延迟功能:

(defn dlay [x]
  (do
    (Thread/sleep 1500)
    x))
(defn q [pg]
  (lazy-seq
   (let [a [0 1 2 3 4 5 6 7 8 9 ]]
     (println "q")
     (map #(+ (* pg 10) %) (dlay a)))))
查询功能:

(defn dlay [x]
  (do
    (Thread/sleep 1500)
    x))
(defn q [pg]
  (lazy-seq
   (let [a [0 1 2 3 4 5 6 7 8 9 ]]
     (println "q")
     (map #(+ (* pg 10) %) (dlay a)))))
通缉行为: 我想产生一个无限的惰性序列,这样当我取一个值时,只计算所需的计算

错误但明确的例子:

(drop 29 (take 30 (mapcat q (range))))
如果我没有错的话,它需要评估每个序列,因为它现在真的不知道序列会有多长

你如何获得正确的行为

我试图纠正这种行为:

(defn getq [coll n]
  (nth 
   (nth coll (quot n 10))
   (mod n 10)))

(defn results-seq []
  (let [a (map q (range))]
    (map (partial getq a)
         (iterate inc 0)))) ; using iterate instead of range, this way i don't have a chunked sequence
但是

仍然实现了“不需要的”
q
序列


现在,我验证了
a
是惰性的,iterate和map应该生成惰性序列,因此问题一定出在
getq
上。但我真的不明白它是如何打破我的懒惰的……也许是
nth
在浏览序列时意识到了什么?如果这是真的,那么在这种情况下,是否有可行的替代方案,或者我的解决方案设计不好?

我不同意。您是否希望
(drop 43(take 44(some seq))
只实现第44个元素?在这种情况下,否,
(take 44…
将实现44个元素,其中除一个元素外,其余元素都被
(drop 43…
)删除。是的,我希望这是一个惰性序列。这种情况下的一个工作示例可能是
(drop 43(take 44(mapq(range))
,它只实现了函数q一次,对吗?不,正如@ShannonSeverance所说,你的函数
q
将被调用44次。序列不是随机访问集合。例如,
(nth(iterate inc 10)5)
将给出
15
inc
被调用了5次,即使
iterate
生成了一个惰性序列。解释说,序列是一个逻辑列表抽象。如果您查看
drop
的源代码,您将看到所有被删除的元素都被消耗,直到第一个未被删除的元素。