Frage

Wenn ich versuche, Metadaten zu einer unendlichen faul Sequenz in Clojure hinzuzufügen, erhalte ich einen Stapelüberlauf, und wenn ich die Metadaten entfernen, dann funktioniert es ganz gut. Warum das Hinzufügen der with-meta Makro den faulen seq brechen?

Zuerst eine unendliche seq von einer sehr schönen Zahl erstellen:

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

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

Dann fügen Sie einige Metadaten zu jedem der lazy-Seq-Instanzen:

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

Versuchen Sie, die Meta-Daten eine Ebene nach oben zu bewegen:

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

Hier ist ein Beispiel für Meta-Daten auf einer endlichen Folge:

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

user> (also-works)
(4)
user> (meta (rest (also-works)))
{:a 5}
user> 
War es hilfreich?

Lösung

Da ein LazySeq wertet seinen Körper, sobald Sie withMeta auf dem LazySeq nennen. Sie verlieren Ihre Faulheit.

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

seq() wertet die faule seq Körper, wenn es nicht bereits ausgewertet worden ist. Ihr Code oben hält Aufruf with-meta auf aufeinanderfolgenden faul ASTA, die sie alle, bis der Stapel explodiert auswertet. Ich glaube nicht, dass es zur Zeit eine Möglichkeit, Metadaten zu einem faulen seq hinzuzufügen, ohne dass sie ihren Körper bewerten.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top