Clojure 堆栈溢出使用 recur、lazy seq?

发布于 2024-11-01 20:10:57 字数 1730 浏览 1 评论 0原文

我读过其他人关于 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))))

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

“orig-gen-pair”函数从文件中读取并返回一对短序列,每个序列大约有 10 个项目。

“write-newlabels”函数只是将传递的序列写入磁盘,没有任何其他副作用,也不返回值。

“Pare-keywords”返回一个短序列和“counts”映射的更新版本。

我只是不明白什么惰性序列可能会导致这里的问题!

任何提示将非常感激!

----编辑----

大家好,我已经将我的函数更新为(希望)更符合 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) 结束。堆栈跟踪对我来说没有多大意义,除了它似乎表明正在发生惰性序列混乱。还有更多提示吗?我需要将代码发布到 process-song 调用的函数中吗?谢谢!

I've read other people's questions about having stack overflow problems in Clojure, and the problem tend to be a lazy sequence being built up somewhere. That appears to be the problem here, but for the life of me I can't figure out where.

Here is the code and after the code is a bit of explanation:

(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))))

There is a map stored in "counts" originally retrieved from the function "counted-origlabels". The map have string keys and integer values. It is 600 or so items long and the values are updated during the iteration but the length stays the same, I've verified this.

The "orig-gen-pair" function reads from a file and returns a short pair of sequences, 10 or so items each.

The "write-newlabels" function just rite the passed sequence to the disk and doesn't have any other side effect nor does it return a value.

"Pare-keywords" returns a short sequence and an updated version of the "counts" map.

I just don't see what lazy sequence could be causing the problem here!

Any tips would be very much appreciated!

----EDIT----

Hello all, I've updated my function to be (hopefully) a little more idiomatic Clojure. But my original problem still remains. First, here is the new code:

(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*)))

This still ends with java.lang.StackOverflowError (repl-1:331). The stack trace doesn't mean much to me other than it sure seems to indicate lazy sequence mayhem going on. Any more tips? Do I need to post the code to the functions that process-song calls? Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

迷爱 2024-11-08 20:10:57

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

如果您可以生成一个函数(我们称之为“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)))

I cannot quite grasp what you are trying to do without a little more concrete sample data, but it's very evident you're trying to iterate over your data using recursion. You're making things way more painful on yourself than you need to.

If you can generate a function, let's call it do-the-thing, that operates correctly with a single entry in your map, then you can call (map do-the-thing (counted-origlabels)), and it will apply (do-the-thing) to each map entry in (counted-origlabels), passing a single map entry to do-the-thing as it's sole argument and returning a seq of the return values from do-the-thing.

You also look like you need indexes, this is easily solved as well. You can splice in the lazy sequence (range) as the second argument to do-the-thing, and then you'll have a series of indexes generated with each map entry; however maps in clojure are not sorted by default, so unless you are using a sorted map, this index value is relatively meaningless.

Trying to abstract away what you've writen so far, try something like:

(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)))
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文