1

I am new to Scheme programming and have been trying to understand the control flow of the programs having call-with-current-continuation in them. To be more specific, I want to know when the call to any continuation is invoked where is the control transferred and what happens after that. It would be really helpful if the below mentioned program is considered for the explanation.

(define call/cc call-with-current-continuation)

(define amb-exit '())

(define amb
 (lambda ()
    (call/cc
      (lambda (m)
       (call/cc
         (lambda (f1)
           (set! amb-exit (lambda () (f1 'exit)))
           (m 1)))
       (call/cc
         (lambda (f2)
           (set! amb-exit (lambda () (f2 'exit)))
           (m 2)))
       (call/cc
         (lambda (f3)
           (set! amb-exit (lambda () (f3 'exit)))
           (m 3)))))))

(define back (lambda () (amb-exit)))

Now, I try to run the code this way (define a (amb)) and then I get the value in the terminal like this ;Value: a. Then in the terminal I check the value of a which returns me ;Value: 1. Then I call (back) I get a with the new value ;Value: 2. So on...

I know that when I do (define a (amb) the continuation f1 is invoked in the statement (set! amb-exit (lambda () (f1 'exit))) which transfers the control back to the first inner call/cc and the f1 continuation returns exit.

The thing that I am not able to understand is why the ;Value: a is ;Value: 1 instead of the value exit which is returned by f1? The moment this part (f1 'exit) is executed, control returns back to first inner call/cc abandoning whatever (in this case (m 1)) after it. So, this part (m 1) should never be invoked because the first inner continuation i.e. f1 is returned with exit even before hitting (m 1).

Any helpful comments regarding call-with-current-continuation in Scheme would also be appreciated.

Note: Using MIT/GNU Scheme

New User
  • 31
  • 3
  • I've explained `call/cc` a couple of times, but I believe [this](https://stackoverflow.com/a/22889607/1565698) is the simplest. It takes a while to understand `call/cc` and it really helps to implement a basic scheme compiler. – Sylwester Oct 29 '18 at 00:05

1 Answers1

1

No, when you do (define a (amb)) the continuation f1 is not invoked, because it is behind (i.e. inside) a lambda.

No, (set! amb-exit (lambda () (f1 'exit))) sets amb-exit to the lambda function, and then the control passes to (m 1) which does invoke the continuation m. Which returns 1 from (amb) in (define a (amb)), which thus sets a to 1.

When you later call (back) it calls (amb-exit) which at that point invokes the f1 continuation with (f1 'exit) which returns the value 'exit from the (call/cc (lambda (f1) ...)) form. This value is discarded, and control passes into the (call/cc (lambda (f2) ...)) form, with similar effects.

Will Ness
  • 70,110
  • 9
  • 98
  • 181
  • thanks for the answer. Just to clarify, whenever control reaches a point like (lambda () (f1 'exit)), does it mean the lambda function is returned without executing its body, and later on when this lambda is called with whatever variable it set to, then the body of lambda function gets evaluated? – New User Oct 28 '18 at 18:21
  • 1
    yes, as is usual, evaluating the form `(set! amb-exit (lambda () (f1 'exit)))` means evaluating the argument, i.e. finding its value. and the value of `(lambda () (f1 'exit))` is a lambda function. and only later when that lambda function is called, its body is entered and its forms are evaluated. – Will Ness Oct 28 '18 at 18:28