[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: manipulating continuations

From: Andy Wingo
Subject: Re: manipulating continuations
Date: Thu, 17 Feb 2011 12:08:56 +0100
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/23.2 (gnu/linux)

Hi Thomas,

Thanks for playing around with prompts!  We use them internally in
Guile, but as they are not yet a standard part of Scheme, there's less
awareness of what they're up to.

Your example brings up an interesting point:

On Wed 16 Feb 2011 21:30, Thomas Girod <address@hidden> writes:

>> (use-modules (ice-9 control))
>> (define (foo)
>>   (% (begin
>>        (display "first part\n")
>>        (abort)
>>        (display "second part\n")
>>        (abort)
>>        (display "third time\n"))
>>      (lambda (cont) cont)))
> scheme@(guile-user)> (foo)
> first part
> $1 = #<partial-continuation 906f5e0>
> scheme@(guile-user)> ($1)
> second part
> module/system/repl/repl.scm:98:4: In procedure with-stack-and-prompt:
> module/system/repl/repl.scm:98:4: Throw to key `vm-error' with args `(vm-run 
> "Too few values returned to continuation" ())'.

What's happening here is that $1, the continuation returned in the first
(abort), does not itself include a prompt.

So when you invoke it again, you are running it without an enclosing
prompt -- so when the second (abort) is called, it finds the next
closest prompt with the default prompt tag (as we did not specify one
explicitly), and that prompt is part of the REPL implementation.  It so
happens that the abort handler for the REPL prompt expects at least one
value to be returned to it, via (abort FOO ...); hence this error.
(Though really we should make this error more helpful.)

Why is it implemented this way, you ask?  Well it's to preserve tail
recursion in some cases.  See the first third of the 2007 paper by
Dybvig, Peyton-Jones, and Sabry, "A monadic framework for delimited
continuations", at
Guile's % (or call-with-prompt) corresponds to the -F- operator.

> I guess I'm having a problem very similar to the previous one I encountered,
> linked to the way prompts are built based on call/cc, right ? Are there any
> ways to solve this ?

Prompts are not actually built on call/cc; and indeed they cannot be.

So!  Your real concern was to be able to make coroutines or generators
or something, right?  Let's use a tagged prompt, and use the more
primitive call-with-prompt and abort-to-prompt procedures:

    (define (coroutine proc)
      (let ((tag (make-prompt-tag)))
        (define (yield . args)
          (apply abort-to-prompt tag args))
        (define (handler cont . args)
          (define (resume . args)
            (call-with-prompt tag
              (lambda () (apply cont args))
          (apply values resume args))
        (call-with-prompt tag
          (lambda () (proc yield))

      (lambda (yield)
        (display "first part\n")
        (display "second part\n")
        (display "third time\n")))
    first part
    $2 = #<procedure resume args>

    scheme@(guile-user)> ($2)
    second part
    $3 = #<procedure resume args>

    scheme@(guile-user)> ($3)
    third time

Happy hacking,


reply via email to

[Prev in Thread] Current Thread [Next in Thread]