Переполнение стека Clojure с использованием recur, lazy seq? - PullRequest
5 голосов
/ 16 апреля 2011

Я читал вопросы других людей о проблемах переполнения стека в 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))))

Существует карта, хранящаяся в «счетах», первоначально полученная из функции «счетные оригами». Карта имеет строковые ключи и целочисленные значения. Это 600 или около того элементов длиной, и значения обновляются во время итерации, но длина остается той же, я это подтвердил.

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

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

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

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

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

---- EDIT ----

Привет всем, я обновил свою функцию, чтобы она (надеюсь) стала немного более идиоматичной 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). Трассировка стека ничего не значит для меня, за исключением того, что, кажется, указывает на то, что происходит беспорядочная последовательность событий. Есть еще советы? Нужно ли публиковать код в функциях, которые вызывает песня процесса? Спасибо!

1 Ответ

1 голос
/ 16 апреля 2011

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

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

Вы также выглядите так, как будто вам нужны индексы, это также легко решается. Вы можете склеить ленивую последовательность (диапазон) как второй аргумент, чтобы сделать что-то, и тогда у вас будет ряд индексов, генерируемых с каждой записью карты; однако карты в 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)))
...