Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

I'm reading the r6rs Scheme report and am confused by the explanation of continuations (I find it to be too dense and lacking of examples for a beginner).

What is this code doing and how does it evaluate to 4? Why does call/cc want an argument that's a function of one argument? How is call/cc's argument used?

(+ 1 (call-with-current-continuation
       (lambda (escape)
         (+ 2 (escape 3)))))
          =⇒ 4

This example is from section 1.11 - Continuations.

share|improve this question
    
This should be a perfect question for codereview.stackexchange.com –  AngeloBad Jul 3 '12 at 13:53
1  
No it isn't: according to their FAQ, this question fails a ton of the eligibility criteria ... –  user39685 Jul 3 '12 at 13:58
2  
Definitely not a Code Review question - example code; he's going for understanding, not betterment, wasn't written himself. –  Michael K Jul 3 '12 at 18:44

3 Answers 3

up vote 4 down vote accepted

call/cc takes a function with one argument, because that argument will be populated with the "current continuation". The continuation in this case will return to the point "just after" the call/cc, namely where its return value is being set.

Thus, when you call (escape 3), the rest of the expression (the (+ 2 ...)) is abandoned, and 3 is set as the return value of the call/cc. Thus, the (+ 1 (call/cc ...)) is now evaluated as (+ 1 3), hence the result is 4.

share|improve this answer

Chris' answer is great, but now that I've figured it out I'd like to add a bit more explanation from the perspective of a beginner to continuations.

call/cc examples

I've done (define call/cc call-with-current-continuation) and will use hop (in the manner of "The Seasoned Schemer") to represent the continuation.

ignoring the parameter: normal evaluation

(call/cc
  (lambda (hop)
    (+ 2 3)))
=> 5

hopping the entire expression: also normal evaluation

(call/cc
  (lambda (hop)
    (hop (+ 2 3))))
=> 5

hopping the operator:

(call/cc
  (lambda (hop)
    ((hop +) 2 3))))
=> #<procedure:+>

hopping an operand:

(call/cc
  (lambda (hop)
    (+ 2 (hop 3))))
=> 3

hopping the hopper:

(call/cc
  (lambda (hop)
    (hop hop)))
=> #<continuation>

Basically, using call/cc gives us a way to 'hop' out of an expression, immediately aborting the computation with the specified return value.

There are many more sophisticated ways to use call/cc that I don't understand, but they're not relevant to the OP.

share|improve this answer

This introduction with a lots of examples helped me understand continuations.

Anyway. These are some examples on how to (ab)use continuations:

(define (pair-up x)
    (call/cc (lambda (continuation)
        ;; recursive helper functions
        (define (pair-up-aux x)
        (if (null? x) 
            '()
            (if (null? (cdr x))
                (continuation #f) ; cancel everything and return #f
                (cons (cons (car x) (cadr x)) (pair-up-aux (cddr x)))))) ; build result
        (pair-up-aux x))))

This code takes a list and makes a list of pairs such that (pair-up '(a b c d)) becomes ((a . b) (c . d)). It does so by recursing and chaining conses. When I'm at the end of the list and see that i lack one element to create the last pair I would want to cancel everything and return #f instead. If I did (pair-up '(a b c)) and just returned #f I would have got ((a . b) . #f). The call/cc at the moment gives me chance to change my mind and return something else alltogether even though I have started constructing my return. (continuation #f) returns #f as the result of this procedure since the call/cc is around the functions body. The next example implements a loop with continuations.

(let ((x 0))
    (let ((cont (call/cc (lambda (x) (x x)))))
        (set! x (+ x 1))
        (display x)
        (newline)
        (if (= x 10)
            (display "Finished!\n")
            (cont cont))))

Now this one actually prints 1..10 and calling the continuation will make it do the body of the let several times. I had to use two separate let (or let*) or else x would have been initialized at each run to and x would never ever become 10.

share|improve this answer
    
Nice, thanks!!! –  user39685 Aug 6 '12 at 16:36

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.