добавление метаданных в отложенную последовательность

StackOverflow https://stackoverflow.com/questions/1056061

  •  20-08-2019
  •  | 
  •  

Вопрос

Когда я пытаюсь добавить метаданные в бесконечную ленивую последовательность в Clojure, я получаю переполнение стека, и если я удаляю метаданные, то это работает просто отлично.Почему добавление with-meta макрос прерывает ленивый seq?

Сначала создайте бесконечную последовательность очень хорошего числа:

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

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

Затем добавьте некоторые метаданные к каждому из экземпляров 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]

Попробуйте переместить метаданные на один уровень выше:

(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> 
Это было полезно?

Решение

Потому что a LazySeq оценивает его тело, как только вы вызываете withMeta на LazySeq.Вы теряете свою лень.

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

seq() оценивает тело отложенного seq, если оно еще не было оценено.Ваш приведенный выше код продолжает вызывать with-meta при последовательных ленивых проверках, которые оценивают их все до тех пор, пока стек не взорвется.Я не думаю, что в настоящее время существует какой-либо способ добавить метаданные в lazy seq, не заставляя его оценивать свое тело.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top