Let's look at let/cc
first.
The expression (let/cc k e)
will 1) capture the current continuation (represented as a function) then 2) bind the variable k
to the captured continuation and finally 3) evaluate the expression e
.
A few examples are in order.
If during evaluation of the expression e
, the captured contination k
is not called, then the value of the let/cc
expression is simply the value(s) to which the expression e
evaluated to.
> (+ 10 (let/cc k 32))
42
If on the other hand k
is called with a value v
then the value of the entire let\cc
expression becomes v
.
> (+ 10 (let/cc k (+ 1 (k 2))))
12
Notice that the part (+ _)
around the call (k 2)
is skipped.
The value is return to the continuation of (let/cc ...)
immediately.
The most common use of let/cc
is to mimic the control struct return
known from many statement based languages. Here is the classical is-it-a-leap-year problem:
(define (divisible-by? y k)
(zero? (remainder y k)))
(define (leap-year? y)
(let/cc return
(when (not (divisible-by? y 4))
(return #f))
(when (not (divisible-by? y 100))
(return #t))
(when (not (divisible-by? y 400))
(return #f))
#t))
(for/list ([y (in-range 1898 1906)])
(list y (leap-year? y)))
Now what about throw
? That depends on which throw
we are talking about.
Is it the one from misc1/throw
?
Or perhaps the one from Might's article? http://matt.might.net/articles/programming-with-continuations--exceptions-backtracking-search-threads-generators-coroutines/
Or perhaps you are using the definition
(define (throw k v)
(k v))
If the latter, then you can replace (k v)
in my examples with (throw k v)
.
UPDATE
Note that the continuation bound to k
can be used more than once - it can also be used outside the let/cc
expression. Consider this example:
(define n 0)
(let ([K (let/cc k k)])
(when (< n 10)
(displayln n)
(set! n (+ n 1))
(K K)))
Can you figure out what it does without running it?
Here is a "step by step" evaluation of the nested let/cc
example.
(let/cc k0
((let/cc k1
(k0 (sub1 (let/cc k2
(k1 k2)))))
1))
(let/cc k0
(k2 1))
(let/cc k0
((let/cc k1
(k0 (sub1 1)))
1))
(let/cc k0
((let/cc k1
(k0 0))
1))
0