2011-04-15 6 views
5

J'ai lu les questions d'autres personnes à propos des problèmes de débordement de pile dans Clojure, et le problème a tendance à être une séquence paresseuse qui se construit quelque part. Cela semble être le problème ici, mais pour la vie de moi, je ne peux pas comprendre où.Débordement de la pile Clojure à l'aide de seq, seq?

Voici le code et après le code est un peu d'explication:

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

Il y a une carte enregistrée dans « compte » initialement extraites de la fonction « décompté origlabels ». La carte possède des clés de chaîne et des valeurs entières. Il y a environ 600 éléments et les valeurs sont mises à jour pendant l'itération mais la longueur reste la même, j'ai vérifié cela.

La fonction "orig-gen-pair" lit un fichier et renvoie une courte paire de séquences, d'une dizaine d'éléments chacune.

La fonction "write-newlabels" ne fait que rimer la séquence transmise au disque et n'a aucun autre effet secondaire et ne renvoie pas de valeur. "Pare-keywords" renvoie une courte séquence et une version mise à jour de la carte "counts".

Je ne vois tout simplement pas quelle séquence paresseuse pourrait causer le problème ici!

Tous les conseils seraient très appréciés!

---- ---- EDIT

Bonjour à tous, je l'ai mis à jour ma fonction d'être (je l'espère) un peu plus idiomatiques Clojure. Mais mon problème d'origine demeure. Tout d'abord, voici le nouveau 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*))) 

Cela se termine toujours avec java.lang.StackOverflowError (rempl-1: 331). La trace de la pile ne signifie pas grand-chose pour moi autre chose que cela semble indiquer que la séquence paresseuse se poursuit. D'autres conseils? Ai-je besoin d'afficher le code sur les fonctions qui traitent les appels de chanson? Merci!

Répondre

1

Je n'arrive pas à saisir ce que vous essayez de faire sans données d'échantillon un peu plus concrètes, mais il est très évident que vous essayez d'itérer sur vos données en utilisant la récursivité. Vous faites des choses beaucoup plus douloureuses sur vous-même que nécessaire. Si vous pouvez générer une fonction, appelons cela le fait, qui fonctionne correctement avec une seule entrée dans votre carte, alors vous pouvez appeler (map do-the-thing (counted-origlabels)), et il s'appliquera (do-the-thing) à chaque entrée de map dans (counted-origlabels), passant une seule entrée de map à do-the-thing comme unique argument et renvoyant un seq des valeurs de retour de do-the-thing .

Vous avez également l'air d'avoir besoin d'index, ce qui est également facile à résoudre. Vous pouvez fusionner dans la séquence paresseuse (range) comme deuxième argument à faire-le-chose, et alors vous aurez une série d'index générés avec chaque entrée de la carte; Cependant, les cartes de clojure ne sont pas triées par défaut, donc à moins d'utiliser une carte triée, cette valeur d'index est relativement insignifiante.

Essayer de abstraire ce que vous avez écrit jusqu'à présent, essayer quelque chose comme:

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

Salut, merci pour la réponse. Je ne pense pas que je puisse générer une fonction qui fonctionne correctement avec une seule entrée de la carte. La fonction "pare-mots-clés" a besoin de toutes les entrées pour la carte dont les clés sont contenues dans les séquences "o" et "g".De plus, bien que l'ordre dans lequel les pare-mots sont appelés avec les index n'est pas important, il est important que chaque appel mette à jour la carte afin que l'appel suivant ait la version mise à jour. Donc, je pourrais faire cela pour surmonter le premier problème, mais pas le dernier, correct? – Philip

+0

Oups, touche retour: (carte (partielle fait-le-truc compté-origlabels) ...)? – Philip

+0

En y regardant de plus près, je ne suis pas sûr de comprendre ce que fait la partie (constamment) (counted-origlabels). – Philip

Questions connexes