懒惰重新实现Clojure Interleaving

时间:2016-03-29 23:35:17

标签: clojure lazy-loading

我想重写(我不确定原始实现是否是懒惰的)使用lazy-seq的惰性交错实现这样工作:

(take 4 (lazy-interleave ’( 1 2 3) ’( a b c)))
(1 a 2 b)

我想出了类似的东西,但我不确定它为什么不起作用:

 (defn lazy-interleave [v1 v2]
   (lazy-seq (concat (list (first v1) (first v2))) (lazy-interleave (next v1) (next v2)))
   )

修改

感谢Arthur的回答,这是一个经过修改的工作解决方案:

(defn lazy-interleave [v1 v2]
    (lazy-seq
      (cons (first v1) (cons (first v2) (lazy-interleave (rest v1) (rest v2))))
      )
   )

2 个答案:

答案 0 :(得分:3)

一些重新格式化揭示了问题:

(defn lazy-interleave [v1 v2]
  (lazy-seq
   (concat (list (first v1) (first v2)))
   (lazy-interleave (next v1) (next v2))))

换句话说,您构建的是一个惰性序列,在实现后,将评估(concat (list (first v1) (first v2))),忽略结果,然后尝试评估并返回(lazy-interleave (next v1) (next v2))。这次对lazy-interleave的调用也做了同样的事情,再次放弃了v1v2的第一个元素,依此类推,无限期。

你永远不会到底,因为你没有空检查,因此(next nil)返回nil,它就会在你耗尽两个序列后继续前进。你没有得到StackOverflowError,因为你使用的是懒惰序列而不是递归。

正确的实现如下:

(defn lazy-interleave [v1 v2]
  (when (and (seq v1) (seq v2))
    (lazy-cat [(first v1) (first v2)]
              (lazy-interleave (rest v1) (rest v2)))))

答案 1 :(得分:1)

interleave已经懒惰了:

user> (interleave (take 5 (iterate #(do (println "sequence A:" %) (inc %)) 0))
                  (take 5 (iterate #(do (println "sequence B:" %) (inc %)) 100)))
sequence A: 0
sequence B: 100
sequence A: 1
sequence B: 101
sequence A: 2
sequence B: 102
sequence A: 3
sequence B: 103
(0 100 1 101 2 102 3 103 4 104)


user> (take 4 (interleave (take 5 (iterate #(do (println "sequence A:" %) (inc %)) 0))
                          (take 5 (iterate #(do (println "sequence B:" %) (inc %)) 100))))
sequence A: 0
sequence B: 100
(0 100 1 101)

它的实现核心看起来很像你的例子:

(lazy-seq
      (let [s1 (seq c1) s2 (seq c2)]
        (when (and s1 s2)
          (cons (first s1) (cons (first s2) 
                                 (interleave (rest s1) (rest s2)))))))

除了它也适用于两个以上的序列,因此它有另一个处理该情况的arity。