Subject: bug#18356: Should partial continuations capture the dynamic environment?

From: Mark H Weaver <[email-masked]>
Date: Wed, 15 Oct 2014 12:37:28 -0400

tags 18356 + notabug
close 18356
thanks

Taylan Ulrich Bayirli/Kammer <[email-masked]> writes:
> In short, no: partial continuations in Guile should not (and do not)
> capture their dynamic environment.

I think this requires further explanation, because the above statement
is not quite correct.

Partial continuations do not capture the _entire_ dynamic environment,
but they *do* capture (and later restore) the _part_ of the dynamic
environment that was established between the prompt and abort.

Thinking in terms of 'dynamic-wind', 'abort-to-prompt' unwinds from the
abort to the prompt, and when the partial continuation is later invoked,
it will rewind from the prompt back to the abort before resuming the
computation.

Thinking in terms of dynamic environments, 'abort-to-prompt' captures
the dynamic bindings that were established between the prompt and abort,
and these captured bindings are composed on top of the dynamic
environment of the call site when the partial continuation is later
invoked.

So, for example:

--8<---------------cut here---------------start------------->8---
scheme@(guile-user)> (call-with-prompt
                      'foo
                      (lambda ()
                        (dynamic-wind
                          (lambda () (display "entering\n"))
                          (lambda () (abort-to-prompt 'foo))
                          (lambda () (display "leaving\n"))))
                      (lambda (k) k))
entering
leaving
$1 = #<partial-continuation 10934680>
scheme@(guile-user)> ($1 'hello)
entering
leaving
$2 = hello
--8<---------------cut here---------------end--------------->8---

Above, the 'dynamic-wind' between the prompt and abort is rewound when
invoking the partial continuation.

--8<---------------cut here---------------start------------->8---
scheme@(guile-user)> (dynamic-wind
                       (lambda () (display "entering\n"))
                       (lambda ()
                         (call-with-prompt
                          'foo
                          (lambda () (abort-to-prompt 'foo))
                          (lambda (k) k)))
                       (lambda () (display "leaving\n")))
entering
leaving
$3 = #<partial-continuation 10972810>
scheme@(guile-user)> ($3 'hello)
$4 = hello
--8<---------------cut here---------------end--------------->8---

Above, the 'dynamic-wind' outside of the prompt is _not_ rewound when
invoking the partial continuation.

--8<---------------cut here---------------start------------->8---
scheme@(guile-user)> (define my-param (make-parameter #f))
scheme@(guile-user)> (call-with-prompt
                      'foo
                      (lambda ()
                        (parameterize ((my-param 5))
                          ((abort-to-prompt 'foo))))
                      (lambda (k) k))
$5 = #<partial-continuation 109f9c60>
scheme@(guile-user)> ($5 my-param)
$6 = 5
--8<---------------cut here---------------end--------------->8---

Above, the dynamic binding of 'my-param' to 5 is restored when invoking
the partial continuation, because it was established between the prompt
and abort.

--8<---------------cut here---------------start------------->8---
scheme@(guile-user)> (parameterize ((my-param 5))
                       (call-with-prompt
                        'foo
                        (lambda () ((abort-to-prompt 'foo)))
                        (lambda (k) k)))
$7 = #<partial-continuation 107a37a0>
scheme@(guile-user)> ($7 my-param)
$8 = #f
--8<---------------cut here---------------end--------------->8---

Above, the dynamic-binding of 'my-param' to 5 is _not_ restored, because
it was established outside of the prompt.

      Mark