我想重写(我不确定原始实现是否是懒惰的)使用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))))
)
)
答案 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
的调用也做了同样的事情,再次放弃了v1
和v2
的第一个元素,依此类推,无限期。
你永远不会到底,因为你没有空检查,因此(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。