Pergunta

Quando tento adicionar metadados a uma seqüência preguiçoso infinito em Clojure, recebo um estouro de pilha, e se eu tirar os metadados, em seguida, ele funciona muito bem. Por que adicionar a macro pausa with-meta o seq preguiçoso?

Primeiro criar uma seq infinito de um número muito bom:

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

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

Em seguida, adicione um pouco de metadados para cada uma das instâncias 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]

Tente mover os dados de meta para um nível acima:

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

Aqui está um exemplo de meta dados em uma sequência finita:

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

user> (also-works)
(4)
user> (meta (rest (also-works)))
{:a 5}
user> 
Foi útil?

Solução

Porque um LazySeq avalia seu corpo assim que você chamar withMeta na LazySeq. Você perde sua preguiça.

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

seq() avalia o corpo do seq preguiçoso se ele já não foi avaliada. Seu código acima continua chamando with-meta em sucessivas As PDCs preguiçosos, que todos eles avalia até que explode pilha. Eu não acho que não há atualmente nenhuma maneira de adicionar metadados a uma seq preguiçoso, sem causar-lo para avaliar o seu corpo.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top