A typical application of control operators is to provide non-local exits, similar to exceptions. The following program which computes the product of the elements of a list and immediately returns 0 if any element of the list is 0 serves as an example.
(define (product xs)
(call-with-current-continuation
(lambda (c)
(let loop ((xs xs))
(cond
((null? xs) 1)
((zero? (car xs)) (c 0))
(else (* (car xs) (loop (cdr xs)))))))))
If xs is dynamic,
binding-time analysis (slightly modified wrt. [7])
yields the following two-level code (see below for a formal definition of
two-level terms):
(define (product xs)
(call-with-current-continuation
(lambda (c : d -> d)
(let loop ((xs xs))
(_cond
((_null? xs) (_lift 1))
((_zero? (_car xs)) (@ c (_lift 0)))
(else (_* (_car xs) (loop (_cdr xs)))))))))
Apparently, the call-with-current-continuation can be executed
statically, at specialization time, with a continuation c, which maps
dynamic to dynamic (code to code). However, the effect is disastrous: The
specializer starts constructing a variant product-0 of
product, captures the continuation, and continues generating a
specialized function loop-0 for the loop because of the dynamic
conditional (_cond ...) [6]. Then it
constructs the body
of loop-0. As the specializer reaches the first branch of the second
conditional ((zero? (car xs))) the captured continuation is applied to
0. Hence, specialization of loop-0 is indefinitely suspended
and the generated code(define (product-0 xs) 0)is clearly wrong.
There are three basic problems in the interaction of call/cc with the specializer.