Friedman and Haynes already use cobs to tackle the problem of defining an unwind-protect (and the corresponding call/cc variant) for Scheme, and observe that there is a choice of meaningful unwind-protect semantics -- the choice as they see it lying in the method of identifying which postludes to perform based purely on their position relative to the continuation nodes in the control tree.
However, automatic detection of the relevant postludes does not necessarily match user expectations. Sometimes it may be more suitable to allow the user explicitly specify which continuations, or continuation calls, ought to trigger unwind-protect postludes, as Kent Pitman [9] proposes. He suggests that call/cc as provided in the Scheme standard may be fundamentally misdesigned as it thwarts the creation of a pragmatic unwind-protect facility, and that it be replaced by one of two call/cc-like operators that he describes as more unwind-protect-friendly, while still providing full continuations.
Fortunately, the cob technique can implement both the Pitman variants, as we shall show in sections 4 and 5. Thus, at least as far as unwind-protect is concerned, Scheme's design does not pose a disadvantage. Indeed, given the variety of unwind-protect styles that are possible for Scheme (it's unlikely that the Friedman-Haynes and Pitman styles exhaust this list), learning the cob technique as a reliable and flexible way to implement the styles may be a better approach than enshrining one of the styles permanently in the standard.
Pitman's first call/cc variant, which we will call call/cc-e, takes an additional argument whose boolean value decides if the captured continuation should be an escaping or a full continuation. Escaping continuations cannot be used to re-enter an already exited dynamic context, whereas full continuations have no such limitation. Thus, in the expressions:
(call/cc-e #t M) (call/cc-e #f N)
M is called with an escaping continuation, whereas N is called with a full continuation.
In a Scheme with call/cc-e, for the expression (unwind-protect B P), the postlude P is run only if (1) B exits normally, or (2) B calls an escaping continuation that was captured outside the unwind-protect expression's dynamic extent.
Pitman's second call/cc variant, which we will call call/cc-l, produces continuations which take an additional argument that decides if that continuation call is to be the last use of that continuation. Thus, when evaluating the following expressions:
(define r 'to-be-set-below) (call/cc-l (lambda (k) (set! r k))) (r #f 'first-use-works) (r #f 'second-use-works) (r #t 'third-use-works-and-is-last-use) (r #f 'fourth-attempted-use-will-not-work)
the fourth attempted use of the continuation r will error.
In a Scheme with call/cc-l, for the expression (unwind-protect B P), the postlude P is run only if (1) B exits normally, or (2) B calls a continuation for the (user-specified) last time, and that continuation does not represent a context that is dynamically enclosed by the unwind-protect expression.
In short, for call/cc-e, postludes are triggered only by continuations specified by the user to be escaping; and for call/cc-l, they are triggered only by continuation calls specified by the user to be their last use.
We will now use the cob technique to define each of these call/cc variants, and its corresponding unwind-protect, from call/cc-f (which we defined in section 2 from the primitive call/cc, also using a cob).