Clojure Interleaving 的惰性重新实现
lazy re-implementation of Clojure Interleaving
我想重写(我不确定原来的实现是否懒惰)一个使用 lazy-seq
的 clojure 交错的懒惰实现,它的工作原理如下:
(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)))
)
编辑:
感谢亚瑟的回答,这是一个修改后的工作解决方案:
(defn lazy-interleave [v1 v2]
(lazy-seq
(cons (first v1) (cons (first v2) (lazy-interleave (rest v1) (rest v2))))
)
)
稍微重新格式化一下就会发现问题:
(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)))
,忽略结果,然后尝试计算 return (lazy-interleave (next v1) (next v2))
。对 lazy-interleave
的调用做同样的事情,再次删除 v1
和 v2
的第一个元素,依此类推,无穷无尽。
你永远不会到达底部,因为你没有空检查,所以自从 (next nil)
returns nil
,即使你用完了两个序列,它也会继续下去。你没有得到 WhosebugError
因为你使用的是惰性序列而不是递归。
正确的实现应该是这样的:
(defn lazy-interleave [v1 v2]
(when (and (seq v1) (seq v2))
(lazy-cat [(first v1) (first v2)]
(lazy-interleave (rest v1) (rest v2)))))
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)))))))
除了它也适用于两个以上的序列,所以它有另一个处理这种情况的参数。
我想重写(我不确定原来的实现是否懒惰)一个使用 lazy-seq
的 clojure 交错的懒惰实现,它的工作原理如下:
(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)))
)
编辑:
感谢亚瑟的回答,这是一个修改后的工作解决方案:
(defn lazy-interleave [v1 v2]
(lazy-seq
(cons (first v1) (cons (first v2) (lazy-interleave (rest v1) (rest v2))))
)
)
稍微重新格式化一下就会发现问题:
(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)))
,忽略结果,然后尝试计算 return (lazy-interleave (next v1) (next v2))
。对 lazy-interleave
的调用做同样的事情,再次删除 v1
和 v2
的第一个元素,依此类推,无穷无尽。
你永远不会到达底部,因为你没有空检查,所以自从 (next nil)
returns nil
,即使你用完了两个序列,它也会继续下去。你没有得到 WhosebugError
因为你使用的是惰性序列而不是递归。
正确的实现应该是这样的:
(defn lazy-interleave [v1 v2]
(when (and (seq v1) (seq v2))
(lazy-cat [(first v1) (first v2)]
(lazy-interleave (rest v1) (rest v2)))))
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)))))))
除了它也适用于两个以上的序列,所以它有另一个处理这种情况的参数。