# Factor and continuations

## Chris Double — 2004-06-07 06:58:02

    I'm experimenting with writing generators and coroutines and thought I'd

    post the findings here in case others have questions.

    For a coroutine code I wanted to create a continuation that when called

    returns back to the current caller, not the original caller when the

    continuation was captured.

    Here's some code:

    : test

    	[ "test1 escaping continuation is " print

    	  dup print

    	  test2

            ] callcc1

    	"end-of-test" print ;

    : test2 ( escape -- )

    	"test2 will call escape continuation" print

    	dup print

    	[

    		"test2 continuation to re-enter is " print

    		dup print

    		swap call

    	] callcc1

    	nip

    	"Stack after calling of test2s re-enter continuation is" print

    	.s

    	call ;

    : test3 ( cont -- )

    	"calling test2s re-enter continuation" print

    	dup print

    	[

    		"test3 escaping continuation which test should call is" print dup print

    		swap call

    	] callcc0

    	drop

    	"test3-end" print ;

    The intent is to provide a continuation in 'test2' that can be called to

    re-enter test2 but exit to the caller of the continuation, not to the

    original caller of 'test2'. So calling 'test' will return to

    "end-of-test" and calling test3 on the continuation returned by 'test'

    will return to 'test3-end'.

    So I'll call 'test', which will place the continuation on the stack. Then

    call 'test3' which calls that continuation and passes it the continuation

    to call to exit back. I'm printing out the values of the continuations so

    I can keep track of what is happening.

        343] clear

        344] .s

        345] test

    test1 escaping continuation is

    [ #<factor.FactorArrayStack@120dbf3> #<factor.FactorCallStack@4845aa>

    #<factor.FactorArrayStack@d5c0f9> [ unit ] continue ]

    test2 will call escape continuation

    [ #<factor.FactorArrayStack@120dbf3> #<factor.FactorCallStack@4845aa>

    #<factor.FactorArrayStack@d5c0f9> [ unit ] continue ]

    test2 continuation to re-enter is

    [ #<factor.FactorArrayStack@1701bdc> #<factor.FactorCallStack@1353249>

    #<factor.FactorArrayStack@1786286> [ unit ] continue ]

    end-of-test

    346] .s

    [ #<factor.FactorArrayStack@1701bdc> #<factor.FactorCallStack@1353249>

    #<factor.FactorArrayStack@1786286> [ unit ] continue ]

    And this is the continuation that I will want to call when running

    'test3'. Note that it is the one from the 'test2 continuation to re-enter

    is' line which is correct.

        346] dup

        347] test3

    calling test2s re-enter continuation

    [ #<factor.FactorArrayStack@1701bdc> #<factor.FactorCallStack@1353249>

    #<factor.FactorArrayStack@1786286> [ unit ] continue ]

    test3 escaping continuatoin which test should call is

    [ #<factor.FactorArrayStack@8c5ea2> #<factor.FactorCallStack@198defc>

    #<factor.FactorArrayStack@1579a30> [ unit ] continue ]

    Stack after calling of test2s re-enter continuation is

    [ #<factor.FactorArrayStack@120dbf3> #<factor.FactorCallStack@4845aa>

    #<factor.FactorArrayStack@d5c0f9> [ unit ] continue ]

    [ #<factor.FactorArrayStack@8c5ea2> #<factor.FactorCallStack@198defc>

    #<factor.FactorArrayStack@1579a30> [ unit ] continue ]

    test3-end

    This works fine. Because of the 'dup' I can recall it by running 'test3'

    and it works again, and again. Nice!

    A couple of points that tripped me up when first experimenting:

    1) I can't just 'call' the continuation captured by 'test2'. If I do this

    I'll end up returning back to 'test' with its stack restored rather than

    where I want to be in the current call stack. This is why 'test3' is used

    to capture a new escaping continuation and pass it to the continuation

    I'm calling.

    2) I got confused by what state the stack should be after calling a

    continuation. I had to remember to drop items off the stack that I no

    longer needed after the 'callcc0' or 'callcc1' call as the stack is

    restored to the point after callcc0 or callcc1 has popped the code to be

    executed off the stack. So:

        : x ( a b c -- ) [ >r drop drop drop r> call ] callcc0 .s ;

        1 2 3 x ( 1 2 3 -- )

        : y ( a b c -- ) [ drop drop drop drop ] callcc1 .s ;

        1 2 3 y ( -- )

    This is why there is the 'nip' in 'test2' and the 'drop' in test3 after

    the callcc.

    Am I understanding how continuations work in Factor correctly?

    Chris.

    --

      Chris Double

      chris.double@...