Hi Matthew,<div><br></div><div>Thanks for your help. †I really can&#39;t even pretend to understand the make-coroutine code but†this is what I&#39;m seeing:</div><div><br></div><div>Original make-coroutine, without stream-ref pre-call =&gt; out of memory (1GB) when running†(prime-pi 500000)</div>
<div>Original make-coroutine, with stream-ref pre-call =&gt; runs (prime-pi 500000) in about .4 sec</div><div>Alternate make-coroutine, with or without stream-ref pre-call =&gt;†runs (prime-pi 500000) in about 28 sec</div>
<div><br></div><div>All runs from &quot;clean&quot; state.</div><div><br></div><div>-joe</div><div><br><div class="gmail_quote">On Tue, Feb 21, 2012 at 10:25 AM, Matthew Flatt <span dir="ltr">&lt;<a href="mailto:mflatt@cs.utah.edu">mflatt@cs.utah.edu</a>&gt;</span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">I don&#39;t know the answer, but here&#39;s a piece of the puzzle that might be<br>
relevant.<br>
<br>
Try this alternate `make-coroutine&#39;:<br>
<br>
†(define (make-coroutine fn)<br>
 † (let ([cont #f])<br>
 † † (Ž ()<br>
 † † † †(call-with-continuation-prompt<br>
 † † † † (lambda ()<br>
 † † † † † (if cont<br>
 † † † † † † † (cont)<br>
 † † † † † † † (fn (Ž () (let/cc k<br>
 † † † † † † † † † † † † † (set! cont k)<br>
 † † † † † † † † † † † † † (abort-current-continuation<br>
 † † † † † † † † † † † † † †(default-continuation-prompt-tag)<br>
 † † † † † † † † † † † † † †void))))))))))<br>
<br>
The difference between this one and the one on the web page is that it<br>
uses a prompt to avoid capturing the continuation of the initial call<br>
to a coroutine (i.e., it uses a delimited continuation for the<br>
coroutine). For me, this variant makes `(prime-pi 500000)&#39; work without<br>
``(stream-ref prime-stream (inexact-&gt;exact (* 0.1 n)))&#39;.<br>
<br>
My guess is that avoiding capture of continuations converts O(N^2)<br>
space usage into O(N) space for some N-deep forcing of streams. Using<br>
`(stream-ref prime-stream (inexact-&gt;exact (* 0.1 n)))&#39;, meanwhile,<br>
might similarly avoid an N-deep nesting at the point where O(N^2)<br>
behavior would kick in.<br>
<br>
I haven&#39;t studied the code enough to be certain that my explanation is<br>
right, but when I see surprising space consumption with laziness and<br>
undelimited continuations, my first guess is that undelimited<br>
continuations are holding onto too much.<br>
<div><div class="h5"><br>
At Mon, 20 Feb 2012 17:19:02 -0800, Joe Gilray wrote:<br>
&gt; Hi,<br>
&gt;<br>
&gt; I created an infinite stream of primes (using this interesting article:<br>
&gt; <a href="http://matthias.benkard.de/journal/116" target="_blank">http://matthias.benkard.de/journal/116</a>)<br>
&gt;<br>
&gt; I tried to create a prime-pi function:<br>
&gt;<br>
&gt; † (define (prime-pi n)<br>
&gt; † † (let loop-count ([candidate-stream prime-stream])<br>
&gt; † † † (if (&gt; (stream-first candidate-stream) n)<br>
&gt; † † † † † 0<br>
&gt; † † † † † (+ (loop-count (stream-rest candidate-stream)) 1))))<br>
&gt;<br>
&gt; (prime-pi 500000) grinds and runs out of memory<br>
&gt;<br>
&gt; But this little cludge makes it run just fine:<br>
&gt;<br>
&gt; † (define (prime-pi n)<br>
&gt; † † (stream-ref prime-stream (inexact-&gt;exact (* 0.1 n))) †; cludge added to<br>
&gt; get the stream to pre-create enough primes<br>
&gt; † † (let loop-count ([candidate-stream prime-stream])<br>
&gt; † † † (if (&gt; (stream-first candidate-stream) n)<br>
&gt; † † † † † 0<br>
&gt; † † † † † (+ (loop-count (stream-rest candidate-stream)) 1))))<br>
&gt;<br>
&gt; What am I not understanding?<br>
&gt;<br>
&gt; Thanks,<br>
&gt; -Joe<br>
</div></div>&gt; ____________________<br>
&gt; † Racket Users list:<br>
&gt; † <a href="http://lists.racket-lang.org/users" target="_blank">http://lists.racket-lang.org/users</a><br>
</blockquote></div><br></div>