Переполнение стека Clojure с использованием повторяющейся, ленивой последовательности?

Я читал вопросы других людей о проблемах с переполнением стека в Clojure, и проблема, как правило, заключается в том, что где-то создается ленивая последовательность. Кажется, здесь проблема, но хоть убей, я не могу понять, где.

Вот код, а после него небольшое пояснение:

(defn pare-all []
  "writes to disk, return new counts map"
(loop [counts (counted-origlabels)
     songindex 0]
(let [[o g] (orig-gen-pair songindex)]
  (if (< songindex *song-count*) ;if we are not done processing list
    (if-not (seq o) ;if there are no original labels
      (do
        (write-newlabels songindex g);then use the generated ones
        (recur counts (inc songindex)))
      (let [{labels :labels new-counts :countmap} (pare-keywords o g counts)] ;else pare the pairs
        (write-newlabels songindex labels)
        (recur new-counts (inc songindex))))
    counts))))

В «counts» хранится карта, первоначально полученная из функции «countted-origlabels». На карте есть строковые ключи и целочисленные значения. Его длина составляет около 600 элементов, и значения обновляются во время итерации, но длина остается неизменной, я это проверил.

Функция "orig-gen-pair" читает из файла и возвращает короткую пару последовательностей, по 10 или около того элементов в каждой.

Функция "write-newlabels" просто записывает переданную последовательность на диск и не имеет никаких других побочных эффектов и не возвращает значение.

«Пар-ключевые слова» возвращает короткую последовательность и обновленную версию карты «подсчетов».

Я просто не понимаю, какая ленивая последовательность может вызывать здесь проблему!

Любые советы будут очень признательны!

----РЕДАКТИРОВАТЬ----

Привет всем, я обновил свою функцию, чтобы (надеюсь) она стала немного более идиоматичной Clojure. Но моя первоначальная проблема все еще остается. Во-первых, вот новый код:

(defn process-song [counts songindex]
  (let [[o g] (orig-gen-pair songindex)]
(if-not (seq o) ;;if no original labels
  (do
    (write-newlabels songindex g);then use the generated ones
    counts)
  (let [{labels :labels new-counts :countmap} (pare-keywords o g counts)] ;else pare the pairs
    (write-newlabels songindex labels)
    new-counts))))

(defn pare-all []
  (reduce process-song (counted-origlabels) (range *song-count*)))

Это все еще заканчивается java.lang.StackOverflowError (repl-1: 331). Трассировка стека для меня ничего не значит, кроме того, что она наверняка указывает на происходящий беспорядок, связанный с ленивой последовательностью. Есть еще советы? Нужно ли мне публиковать код для функций, которые обрабатывают вызовы песни? Спасибо!


person Philip    schedule 15.04.2011    source источник


Ответы (1)


Я не могу понять, что вы пытаетесь сделать без более конкретных данных, но совершенно очевидно, что вы пытаетесь перебрать свои данные с помощью рекурсии. Вы причиняете себе гораздо больше боли, чем нужно.

Если вы можете сгенерировать функцию, назовем ее do-the-thing, которая правильно работает с одной записью на вашей карте, затем вы можете вызвать (map do-the-thing (countted-origlabels)), и она будет применяться ( do-the-thing) для каждой записи карты в (countted-origlabels), передавая одну запись карты to-do-вещь в качестве единственного аргумента и возвращая seq возвращаемых значений от do-the-thing.

Вы тоже выглядите так, будто вам нужны индексы, это тоже легко решается. Вы можете вставить ленивую последовательность (диапазон) в качестве второго аргумента для выполнения задачи, и тогда у вас будет серия индексов, сгенерированных для каждой записи карты; однако карты в clojure по умолчанию не сортируются, поэтому, если вы не используете отсортированную карту, это значение индекса относительно бессмысленно.

Пытаясь абстрагироваться от того, что вы написали, попробуйте что-нибудь вроде:

(defn do-the-thing [entry index counts]
  (let [[o g] (orig-gen-pair index)]
    (if-not (seq o)
      (write-newlabels index g)
      (let [{labels :labels new-counts :countmap} (pare-keywords o g counts)]
        (write-newlabels index labels)))))

(map do-the-thing (counted-origlabels) (range) (constantly (counted-origlabels)))
person animal    schedule 15.04.2011
comment
Привет, спасибо за ответ. Я не думаю, что смогу сгенерировать функцию, которая корректно работает с одной записью с карты. Функция pare-keywords требует всех записей для карты, ключи которых содержатся в последовательностях o и g. Кроме того, хотя порядок, в котором парные ключевые слова вызываются с индексами, не важен, важно, чтобы каждый вызов обновлял карту, чтобы последующий вызов имел обновленную версию. Итак, я мог бы сделать это, чтобы решить первую проблему, но не вторую, верно? - person Philip; 16.04.2011
comment
Ой, нажмите return: (карта (частичные подсчитанные оригинальные метки) ...)? - person Philip; 16.04.2011
comment
При ближайшем рассмотрении я не уверен, что понимаю, что делает часть (постоянно (count-origlabels)). - person Philip; 16.04.2011
comment
Я совершенно ошибаюсь, когда использую постоянно, и вместо этого должен был использовать (repeat (countted-origlabels)). Постоянно возвращает функцию, которая постоянно возвращает заданное вами значение. Repeat превращает бесконечную последовательность, каждый элемент которой является значением, которое вы ему придаете. Используя (repeat (countted-origlabels), у вас всегда будет полная карта, доступная при каждом вызове для выполнения задачи. - person animal; 16.04.2011
comment
Трудно попытаться понять, что вы делаете, без дополнительного контекста, но похоже, что вы хотите записать какое-то значение на диск для каждого значения на карте. Вы также хотите потенциально изменить каждое значение на этой карте в зависимости от некоторого условия. Разъедините эти проблемы, сначала примените условное изменение к каждому значению в исходной карте, чтобы сгенерировать новую карту. Затем запишите соответствующие значения из вашей новой карты на диск. Я понимаю, что такие утверждения о том, что делать что-то совершенно по-другому, могут показаться не очень полезными. Думаю, вам действительно понравятся результаты, если вы их попробуете. - person animal; 16.04.2011