Continuations are a freezed state that is encapsulated by a lambda and can resstart at the stored location when one executes the lambda. Delimited continuations means that one can compose the continuations freely and basically mean thta from a control point the continuation evaluation returns what the lambda inside the control point returns, delimited continuations can therefore be construted and used like any other funciton in a composable way, normal continuatins can be more difficult to handle and does not compose nicely. The delimited continuation goal will fail if the enclosing code fails and it will fail according to the new setup. Also when a delimeted continuation goal succeeds if the continuated enclosed code suceeds (that we restarted in) and the goal works just like any other goal.
with_prompt(tag,code,handler_data,handler), The enclosing code is
code, which will first executed, if inside this, a
abort_to_prompt is executed with a
tag, matching this ideoms
tag, then the
handler will be executed with
handler_data unified to,
handler_data = [intag,next,kont,data_from_abort], The actual intag will be
intag. A goal,
next(), will be supplied which can be used to instruct the code to search for the next handler if executed. The actual continuation goal
kont, is supplied as well as data send from the
kont is a term with one argument and is executed like
call_k(kont,Arg), sending an
Arg to the restart to the continuation.
kont is live for the rest of the execution and the handler will at backtracking fail the whole
call_k(kont,A), execute a continuation goal.
abort_to_prompt(tag,data_to_handler, data_from_continuation), will abort with tag
tag, for which a handler is searched.
data_to_handler, is data sent to the handler, and
data_from_continuation, is the data that is put inside the argument of the continuation.
re_prompt(tag,kont,handle_data handle kont_data))
re_prompt(kont,handle_data handle kont_data)) (old tag is reused),
an efficiency hack to handle the case when a continuation is executed, but with a new handler in stead of the old one that that continuation came from. This is useful because with this a generator built with this tool does not build up stack.
(use-modules (logic guile-log guile-prolog continuations)) /* produce a value X to the user */ yield(X) :- abort_to_prompt(generator,X,_). /* consume a value X from the user */ eat(X) :- abort_to_prompt(generator,_,X). /* execute Goal and put the resulting generator state in F */ generator(Goal,F) :- with_prompt(generator, Goal,[generator,_,K,X], F=[K,X]). /* [K,X] is the state argument, X will be the next value argument, F will bind to the new state */ next([K,X],X,F) :- re_prompt(K,[generator,_,K2,XX],F=[K2,XX],_). /* same as next, but Y will be a value fed to the consumer generator */ feed([K,_],Y,F) :- re_prompt(K,[generator,_,K2,_ ],F=[K2,_ ],Y). /* the full two way ideom */ translate([K,X],X,Y,F) :- re_prompt(K,[generator,_,K2,XX],F=[K2,XX],Y). /* sum consumes via eat(X) and add X to the S */ sum(S) :- eat(X), SS is S + X, sum(SS). /* yields N,N+1,..,9 */ iter(N) :- N < 10 -> ( yield(N), N2 is N + 1, iter(N2) ). /* create a producer F and a consumer S */ run :- generator(iter(0),F), generator(sum(0),S), pr(F,S). /* transfers data from the producer to the feeder */ pr(F,S) :- next(F,X,FF) -> feed(S,X,SS), pr(FF,SS).