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 ... –  Matt Fenwick 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 5 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!!! –  Matt Fenwick Aug 6 '12 at 16:36

Your Answer

 
discard

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.