当我尝试在Clojure中向无限延迟序列添加元数据时,我得到了堆栈溢出,如果我取消元数据,那么它的工作正常。为什么添加with-meta
宏会破坏懒惰的seq?
首先创建一个非常好的数字的无限序列:
(defn good [] (lazy-seq (cons 42 (good)))) user> (take 5 (good)) (42 42 42 42 42)
然后,为每个lazy-seq实例添加一些元数据:
(defn bad [] (lazy-seq (cons 42 (with-meta (bad) {:padding 4})))) user> (take 5 (bad)) java.lang.StackOverflowError (NO_SOURCE_FILE:0) [Thrown class clojure.lang.Compiler$CompilerException]
尝试将元数据向上移动一级:
(defn also-bad [] (with-meta (lazy-seq (cons 42 (also-bad))) {:padding 4})) user> (take 5 (foo)) java.lang.StackOverflowError (NO_SOURCE_FILE:0) [Thrown class clojure.lang.Compiler$CompilerException]
以下是有限序列的元数据示例:
(defn also-works [] (lazy-seq (cons 4 (with-meta () {:a 5})))) user> (also-works) (4) user> (meta (rest (also-works))) {:a 5} user>
答案 0 :(得分:6)
因为LazySeq
会在withMeta
上致电LazySeq
后评估其正文。你失去了懒惰。
public final class LazySeq extends Obj implements ISeq, List{
...
public Obj withMeta(IPersistentMap meta){
return new LazySeq(meta, seq());
}
...
}
seq()
评估惰性seq的主体(如果尚未评估)。上面的代码一直在连续的延迟seq上调用with-meta
,它会对它们进行全局计算,直到堆栈爆炸。我认为目前没有任何方法可以将元数据添加到惰性seq而不会导致它评估其正文。