Note that there are some explanatory texts on larger screens.

plurals
  1. PO(Another) Stack overflow on loop-recur in Clojure
    text
    copied!<p>Similar questions: <a href="https://stackoverflow.com/q/9202500/2472391">One</a>, <a href="https://stackoverflow.com/q/10237880/2472391">Two</a>, <a href="https://stackoverflow.com/q/4249926/2472391">Three</a>.</p> <p>I am thoroughly flummoxed here. I'm using the <a href="http://clojure.org/special_forms#Special%20Forms--%28recur%20exprs*%29" rel="nofollow noreferrer">loop-recur</a> form, I'm using <a href="http://clojuredocs.org/clojure_core/clojure.core/doall" rel="nofollow noreferrer">doall</a>, and still I get a stack overflow for large loops. My Clojure version is 1.5.1.</p> <p>Context: I'm training a neural net to mimic XOR. The function <code>xor</code> is the feed-forward function, taking weights and input and returning the result; the function <code>b-xor</code> is the back-propagation function that returns updated weights given the results of the last call to <code>xor</code>.</p> <p>The following loop runs just fine, runs very fast, and returns a result, and based off of the results it returns, it is training the weights perfectly:</p> <pre class="lang-clj prettyprint-override"><code>(loop [res 1 ; &lt;- initial value doesn't matter weights xorw ; &lt;- initial pseudo-random weights k 0] ; &lt;- count (if (= k 1000000) res (let [n (rand-int 4) r (doall (xor weights (first (nth xorset n))))] (recur (doall r) (doall (b-xor weights r (second (nth xorset n)))) (inc k))))) </code></pre> <p>But of course, that only gives me the result of the very last run. Obviously I want to know what weights have been trained to get that result! The following loop, with nothing but the return value changed, overflows:</p> <pre class="lang-clj prettyprint-override"><code>(loop [res 1 weights xorw k 0] (if (= k 1000000) weights ; &lt;- new return value (let [n (rand-int 4) r (doall (xor weights (first (nth xorset n))))] (recur (doall r) (doall (b-xor weights r (second (nth xorset n)))) (inc k))))) </code></pre> <p>This doesn't make sense to me. The entirety of <code>weights</code> gets used in each call to <code>xor</code>. So why could I use <code>weights</code> internally but not print it to the REPL?</p> <p>And as you can see, I've stuck <code>doall</code> in all manner of places, more than I think I should need. XOR is a toy example, so <code>weights</code> and <code>xorset</code> are both very small. I believe the overflow occurs not from the execution of <code>xor</code> and <code>b-xor</code>, but when the REPL tries to print <code>weights</code>, for these two reasons:</p> <p>(1) this loop can go up to 1500 without overflowing the stack.</p> <p>(2) the time the loop runs is consistent with the length of the loop; that is, if I loop to 5000, it runs for half a second and then prints a stack overflow; if I loop to 1000000, it runs for ten seconds and then prints a stack overflow -- again, only if I print <code>weights</code> and not <code>res</code> at the end.</p> <p>(3) EDIT: Also, if I just wrap the loop in <code>(def w ... )</code>, then there is no stack overflow. Attempting to peek at the resulting variable does, though.</p> <pre><code>user=&gt; (clojure.stacktrace/e) java.lang.StackOverflowError: null at clojure.core$seq.invoke (core.clj:133) clojure.core$map$fn__4211.invoke (core.clj:2490) clojure.lang.LazySeq.sval (LazySeq.java:42) clojure.lang.LazySeq.seq (LazySeq.java:60) clojure.lang.RT.seq (RT.java:484) clojure.core$seq.invoke (core.clj:133) clojure.core$map$fn__4211.invoke (core.clj:2490) clojure.lang.LazySeq.sval (LazySeq.java:42) nil </code></pre> <p>Where is the lazy sequence?</p> <p>If you have suggestions for better ways to do this (this is just my on-the-fly REPL code), that'd be great, but I'm really looking for an explanation as to what is happening in this case.</p> <hr> <p>EDIT 2: Definitely (?) a problem with the REPL.</p> <p>This is bizarre. <code>weights</code> is a list containing six lists, four of which are empty. So far, so good. But trying to print one of these empty lists to the screen results in a stack overflow, but only the first time. The second time it prints without throwing any errors. Printing the non-empty lists produces no stack overflow. Now I can move on with my project, but...what on earth is going on here? Any ideas? (Please pardon the following ugliness, but I thought it might be helpful)</p> <pre><code>user=&gt; (def ww (loop etc. etc. )) #'user/ww user=&gt; (def x (first ww)) #'user/x user=&gt; x StackOverflowError clojure.lang.RT.seq (RT.java:484) user=&gt; x () user=&gt; (def x (nth ww 3)) #'user/x user=&gt; x (8.47089879874061 -8.742792338501289 -4.661609290853221) user=&gt; (def ww (loop etc. etc. )) #'user/ww user=&gt; ww StackOverflowError clojure.core/seq (core.clj:133) user=&gt; ww StackOverflowError clojure.core/seq (core.clj:133) user=&gt; ww StackOverflowError clojure.core/seq (core.clj:133) user=&gt; ww StackOverflowError clojure.core/seq (core.clj:133) user=&gt; ww (() () () (8.471553034351501 -8.741870954507117 -4.661171802683782) () (-8.861958958234174 8.828933147027938 18.43649480263751 -4.532462509591159)) </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload