2006-03-17
Partial Continuations and Factor
I've written some partial continuation support and put it in the Factor contrib directory. It implements bshift and breset as outlined by Oleg's post on comp.lang.scheme.
It's in contrib/partial-continuations.factor and can be pulled from my repository until it makes it to the official Factor repository:
darcs pull http://www.bluishcoder.co.nz/repos/factor
It should be relatively easy to convert Oleg's Scheme examples to Factor. Just remember that the partial continuation has stack effect ( a -- b ) and the quotations passed to bshift and breset have stack effect ( pcc -- v ) and ( -- v ) respectively.
'breset' marks the scope of the partial continuation. If 'bshift' is not used then the value returned by the quotation is left on the stack:
[ drop 5 ] breset
=> 5
An example with 'bshift':
[
1 swap [ 5 swap call ] bshift +
] breset
=> 6
In this case the partial continuation passed to the 'bshift' quotation represents the computation '1 X +' where 'X' is replaced by the value passed to the partial continuation. In this case 5, resulting in a result of 6. Additional calls can be made to the same continuation:
[
1 swap [ 5 over call swap call ] bshift +
] breset
=> 7
This calls the '1 X +' partial continuation twice. First with '5' returning the value '6'. Which is then passed to it again, returning '7'. The partial continuation does not need to be called. Values that 'fall through' cause the result to be returned from the 'breset' quotation:
[
1 swap [ drop 5 ] bshift +
] breset
=> 5
Here's a fun example translated from Oleg's posting. The following 'range' function has some interesting properties:
: range ( r from to -- )
rot [ ( from to pcc -- )
-rot [ over + pick call drop ] each 2drop f
] bshift ;
It uses the standard 'each' call on a 'from' and 'too' number to call a quotation on each number between 'from' and 'too' inclusive. The quotation called is the partial continuation provided by 'bshift'. This can be used in code like:
[ 1 5 range . ] breset drop
=> 1
2
3
4
5
For each item in the range it executed the partial continuation which is 'X .', printing that item in the range. So given a function that knows nothing about the special capability of 'range' can still work with it. The following prints the first five factorials:
: fact ( n -- n ) dup 1 = [ 1 ] [ dup 1 - fact ] if * ;
[ 1 5 range fact . ] breset drop
=> 1
2
6
24
120
I'm not sure how useful delimited continuations are in Factor but it gives something to play with to see how they work.