adição de metadados com uma sequência de preguiçoso
-
20-08-2019 - |
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>
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.