Lisp 向延迟序列添加元数据

Lisp 向延迟序列添加元数据,lisp,clojure,lazy-sequences,Lisp,Clojure,Lazy Sequences,当我试图在Clojure中将元数据添加到一个无限的惰性序列时,我会得到一个堆栈溢出,如果我去掉元数据,那么它就可以正常工作。为什么用meta添加宏会破坏惰性seq 首先创建一个非常好的数字的无限序列: (defn good [] (lazy-seq (cons 42 (good)))) user> (take 5 (good)) (42 42 42 42 42) (定义良好[] (续) (反对意见42) (好) 用户>(取5(好)) (42 42 42 42 42)

当我试图在Clojure中将元数据添加到一个无限的惰性序列时,我会得到一个堆栈溢出,如果我去掉元数据,那么它就可以正常工作。为什么用meta添加
宏会破坏惰性seq

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

(defn good [] (lazy-seq (cons 42 (good)))) user> (take 5 (good)) (42 42 42 42 42) (定义良好[] (续) (反对意见42) (好) 用户>(取5(好)) (42 42 42 42 42) 然后,向每个惰性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] (定义错误[] (续) (反对意见42) (带meta) (坏) {:padding(4}))) 用户>(取5(坏)) java.lang.StackOverflowerr(无源文件:0) [抛出类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也不好[] (带meta) (续) (反对意见42) (也不好) {:填充4}) 用户>(取5(foo)) java.lang.StackOverflowerr(无源文件:0) [抛出类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> (defn也起作用[] (续) (缺点4) (带meta) () {(a:5}))) 用户>(也适用) (4) 用户>(元(rest(也工作))) {:a 5} 用户>
因为只要您在
LazySeq
上调用
withMeta
,一个
LazySeq
就会评估它的主体。你失去了你的懒惰

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

seq()。上面的代码在连续的惰性seq上使用meta
不断调用
,这将对它们进行求值,直到堆栈爆炸为止。我认为目前没有任何方法可以向惰性seq添加元数据,而不让它评估其主体。

惰性seq和with meta都是宏,因此您应该能够进一步了解macroexpand resp。macroexpand-1.FWIW,中的第二个补丁,如果被接受,将提供一种方法。