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>