2009-06-28 16 views
3

Clojureの無限レイジーシーケンスにメタデータを追加しようとすると、スタックオーバーフローが発生し、メタデータを取り除くとうまくいきます。 with-metaマクロを追加すると、遅延セグメントが中断されるのはなぜですか?レイジーシーケンスにメタデータを追加する

まず非常に素晴らしい数の無限の配列を作成:怠惰-seqのインスタンスのそれぞれにいくつかのメタデータを追加し、その後

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

は1までのメタデータを移動してみてくださいレベル:

 
(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

lazy-seqとwith-metaの両方がマクロであるため、macroexpand respを使用してさらに詳しい情報を得ることができます。マクロエクセル-1。 – Svante

答えて

6

LazySeqはできるだけ早くあなたがLazySeqwithMetaを呼び出すと、その本体を評価しますので。あなたはあなたの怠惰を失います。

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

seq()がまだ評価されていない場合は怠惰な配列のボディを評価します。上のコードは、スタックが爆発するまでそれらをすべて評価する、連続した遅延Seqでwith-metaを呼び出し続けます。私は現在、怠け者のseqにメタデータを追加する方法がないと思っていません。

+0

FWIWは、[CLJ-1800](https://dev.clojure.org/jira/browse/CLJ-1800)の2番目のパッチが承認されれば、方法を提供します。 –

関連する問題