Today I received a mail from Hong. Its content is following.
This is an explanation I got from Matthew Flatt today (Matthew is
the author of MzScheme), from his text, the call/cc stack or the stack
frame should be copied to the heap, and then reload it to the
stack when it is required to restore, while in the call/ec, the
stack does not need to be copied to the heap, since it is only
purposed to be used to escape the block:
>> I guess you were try to mention the C's auto, register and volatile
>> variables in the setjmp and longjmp of call/ec block do not need
>> to handle, while in call/cc they all have to be kept somewhere for
>> restore. Is this right?
>
> No, it's a much bigger difference than that. `call/cc' has to copy the
> stack, in case the continuation is invoked after it returns. `call/ec'
> never has to copy the stack, because it can only be used to escape
> while the old part of the stack is still in place.
In short, call/cc is a very nice feature, but it is not cheap (nowadays,
the computers allow this cost though). Call/ec is cheap, it does not
to copy the environmental blocks for restoring.
Note that call/ec is not a standard feature required in R5RS.
I made an example program to show the difference of call/cc and call/ec:
(define-values (x y) (values '() '()))
(+ 1 (call/cc (lambda (k)
(set! x k)
(k 100)
(* 3 7))))
=> 101
which shows the continuation of "adding one" is copied to somewhere
in the heap, and can be called back for the evaluation:
(x 10)
=> 11
For call/ec, try this:
(+ 1 (call/ec (lambda (q)
(set! y q)
(q 100)
(* 3 7))))
=>101 ; same value returned as previous one, but different story underneath.
which shows the stack disappeared (not copied to somewhere in the heap,
but to the sub-stack frame), thus it can not be restored later outside
the block:
(y 10)
=> continuation application: attempt to jump into an escape continuation.
This is an explanation I got from Matthew Flatt today (Matthew is
the author of MzScheme), from his text, the call/cc stack or the stack
frame should be copied to the heap, and then reload it to the
stack when it is required to restore, while in the call/ec, the
stack does not need to be copied to the heap, since it is only
purposed to be used to escape the block:
>> I guess you were try to mention the C's auto, register and volatile
>> variables in the setjmp and longjmp of call/ec block do not need
>> to handle, while in call/cc they all have to be kept somewhere for
>> restore. Is this right?
>
> No, it's a much bigger difference than that. `call/cc' has to copy the
> stack, in case the continuation is invoked after it returns. `call/ec'
> never has to copy the stack, because it can only be used to escape
> while the old part of the stack is still in place.
In short, call/cc is a very nice feature, but it is not cheap (nowadays,
the computers allow this cost though). Call/ec is cheap, it does not
to copy the environmental blocks for restoring.
Note that call/ec is not a standard feature required in R5RS.
I made an example program to show the difference of call/cc and call/ec:
(define-values (x y) (values '() '()))
(+ 1 (call/cc (lambda (k)
(set! x k)
(k 100)
(* 3 7))))
=> 101
which shows the continuation of "adding one" is copied to somewhere
in the heap, and can be called back for the evaluation:
(x 10)
=> 11
For call/ec, try this:
(+ 1 (call/ec (lambda (q)
(set! y q)
(q 100)
(* 3 7))))
=>101 ; same value returned as previous one, but different story underneath.
which shows the stack disappeared (not copied to somewhere in the heap,
but to the sub-stack frame), thus it can not be restored later outside
the block:
(y 10)
=> continuation application: attempt to jump into an escape continuation.