使用recur,lazy seq的Clojure堆栈溢出?

Phi*_*lip 5 clojure overflow lazy-evaluation

我已经阅读了其他人关于在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))))
Run Code Online (Sandbox Code Playgroud)

存储在最初从函数"counting-origlabels"中检索的"计数"中的映射.地图具有字符串键和整数值.它是600左右的项目,并且迭代期间值更新但长度保持不变,我已经验证了这一点.

"orig-gen-pair"函数从文件中读取并返回一对短序列,每个序列有10个左右的项目.

"write-newlabels"函数只是将传递的序列命名为磁盘,没有任何其他副作用,也没有返回值.

"Pare-keywords"返回短序列和"计数"映射的更新版本.

我只是没有看到懒惰的序列可能导致这里的问题!

任何提示将非常感谢!

- - 编辑 - -

大家好,我已经更新了我的功能(希望)更加惯用的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*)))
Run Code Online (Sandbox Code Playgroud)

这仍然以java.lang.StackOverflowError(repl-1:331)结束.堆栈跟踪对我来说并不意味着什么,除了它肯定表明懒惰的序列混乱正在发生.还有什么提示吗?我是否需要将代码发布到处理歌曲调用的函数中?谢谢!

ani*_*mal 1

如果没有更具体的示例数据,我无法完全理解您要做什么,但很明显您正在尝试使用递归来迭代数据。你让事情变得比你需要的更加痛苦。

如果您可以生成一个函数(我们称之为“do-the-thing”),该函数可以通过地图中的单个条目正确运行,那么您可以调用 (map do-the-thing (counted-origlabels)),并且它将应用 ( do-the-thing) 到 (counted-origlabels) 中的每个映射条目,将单个映射条目传递给 do-the-thing 作为唯一参数,并返回 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)))
Run Code Online (Sandbox Code Playgroud)