将元数据添加到延迟序列

时间:2009-06-28 23:45:24

标签: lisp clojure lazy-sequences

当我尝试在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> 

1 个答案:

答案 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而不会导致它评估其正文。