Я пытаюсь сгенерировать последовательность, которая соответствует поиску в ширину очень широкого и глубокого дерева... и у меня возникают проблемы с памятью, когда я захожу слишком далеко по последовательности. Поспрашивав на IRC-канале и посмотрев здесь, причина номер 1 таких проблем — непреднамеренное удержание за голову; но я не вижу, где я это делаю.
Код довольно прост; вот версия, которая отображает проблему:
(def atoms '(a b c))
(defn get-ch [n] (map #(str n %) atoms))
(defn add-ch
([] (apply concat (iterate add-ch atoms)))
([n] (mapcat get-ch n)))
(dorun (take 20000000 (add-ch)))
А вот еще одна версия (с которой я начал до получения помощи от #clojure), которая отображает ту же проблему:
(def atoms '(a b c))
(defn get-children [n] (map #(str n %) atoms))
(defn add-layer
([] (add-layer atoms))
([n] (let [child-nodes (mapcat get-children n) ]
(lazy-seq (concat n (add-layer child-nodes))))))
(dorun (take 20000000 (add-layer)))
Оба дают мне «пространство кучи Java OutOfMemoryError». Я запускаю их из REPL в Eclipse/CounterClockwise на Macbook Air.
Я новичок в Clojure, поэтому, после того, как я целый день ломал голову над этим, я надеюсь, что это что-то тривиальное, что я упускаю из виду. Я понимаю, что мог бы увеличить размер кучи, чтобы уменьшить вероятность возникновения проблемы, но последовательности, которые я в конечном итоге хочу обработать, настолько велики, что я не думаю, что это мне поможет.
Я пытался заменить "дубль" (в приведенных выше примерах) на "бросок", чтобы не держаться за голову - это не имеет значения.