将元数据添加到惰性序列

发布于 2024-07-26 11:13:40 字数 1001 浏览 4 评论 0原文

当我尝试将元数据添加到 Clojure 中的无限惰性序列时,出现堆栈溢出,如果我删除元数据,那么它就可以正常工作。 为什么添加 with-meta 宏会破坏惰性序列?

首先创建一个非常好的数字的无限序列:

(defn good []
  (lazy-seq 
    (cons 42
      (good))))

user> (take 5 (good))
(42 42 42 42 42)

然后,向每个惰性序列实例添加一些元数据:

(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> 

When I try to add metadata to an infinite lazy sequence in Clojure, I get a stack overflow, and if I take off the metadata, then it works just fine. Why does adding the with-meta macro break the lazy seq?

First create an infinite seq of a very nice number:

(defn good []
  (lazy-seq 
    (cons 42
      (good))))

user> (take 5 (good))
(42 42 42 42 42)

Then, add some metadata to each of the lazy-seq instances:

(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]

Try moving the meta data up one level:

(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]

Here is an example of meta data on a finite sequence:

(defn also-works []
     (lazy-seq 
       (cons 4 
         (with-meta 
          () 
          {:a 5}))))

user> (also-works)
(4)
user> (meta (rest (also-works)))
{:a 5}
user> 

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

梦与时光遇 2024-08-02 11:13:40

因为一旦您在 LazySeq 上调用 withMetaLazySeq 就会评估其主体。 你失去了你的懒惰。

public final class LazySeq extends Obj implements ISeq, List{
    ...
    public Obj withMeta(IPersistentMap meta){
        return new LazySeq(meta, seq());
    }
    ...
}

seq() 会评估惰性 seq 的主体(如果尚未评估)。 上面的代码不断在连续的惰性序列上调用 with-meta ,这会评估它们直到堆栈爆炸。 我认为目前没有任何方法可以将元数据添加到惰性序列而不使其评估其主体。

Because a LazySeq evaluates its body as soon as you call withMeta on the LazySeq. You lose your laziness.

public final class LazySeq extends Obj implements ISeq, List{
    ...
    public Obj withMeta(IPersistentMap meta){
        return new LazySeq(meta, seq());
    }
    ...
}

seq() evaluates the lazy seq's body if it hasn't already been evaluated. Your code above keeps calling with-meta on successive lazy seqs, which evaluates them all until the stack explodes. I don't think there's currently any way to add metadata to a lazy seq without causing it to evaluate its body.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文