prologs delimited continuations is documented

parent 04f813fb
......@@ -1888,11 +1888,130 @@ Added ontop of this is how to evolve the state data like asserting new facts or
@node prolog-libraries
@section Prolog libraries exposing guile-log features
There are a few interesting datastructures and algorithm taken from guile-log that can be directly used in guile-log prolog, here we describe them:
* prolog interleaving:: Kanren's interleving constructs.
* prolog continuations:: Delimeted Continuation goals.
* prolog zip:: Evaluating goals in parallell.
* prolog hash:: VHashes and Vlists.
* prolog postpone:: Postpone facilities.
@end menu
@node prolog interleaving
@subsection Interleaving constructs.
Generally prolog empowers a depth first search. But with the interleaving constructs it is at least in principle possible to do a wide search. Especially if there is branches that are huge or infinite, a solver can get stuck in that branch, missing a simple shallow solution in another branch. The interleaving constructs can cure this.
@subsubsection Api
@code{or_i(branch,...)}, will execute @code{branch...} cyclically e.g. first try @code{branch1}, if that fails, then try @code{branch2} and if @code{branch-n}, the end branch fails, then start all over from the beginning with the next try of @code{branch1} and so on.
@code{and_i(factor,...)}, will interleave the backtracking of @code{factor...} when the whole expression backtracks.
@code{or_union(branch,...)}, The same as with @code{or_i}, but any results will be unique.
@subsubsection Examples
/* X = A,A+1,A+2,...,A+10 */
c(X,A) :- c(X,A,0).
c(X,A,N) :- N < 10,
(X = A ; (B is A + 1, M is N + 1, c(X,B,M))).
/* or_i test */
f1(X) :- or_i(c(X,0),c(X,100)).
/* and_i test */
f2(X,Y) :- and_i(c(X,0),c(Y,100)).
/* or_union test */
f3(X) :- or_union(c(X,0),c(X,2)).
(prolog-run 10 (X) (f1 X))
$1 = (0 100 1 101 2 102 3 103 4 104)
(prolog-run 10 (X Y) (f2 X Y))
$2 = ((0 100) (1 100) (0 101) (2 100) (1 101)
(0 102) (3 100) (2 101) (1 102) (0 103))
(prolog-run 10 (X) (f3 X))
$3 = (0 2 1 3 4 5 6 7 8 9)
@end verbatim
@node prolog continuations
@subsection Delimited continuation goals.
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.
@subsubsection Api
@code{with_prompt(tag,code,handler_data,handler)}, The enclosing code is @code{code}, which will first executed, if inside this, a @code{abort_to_prompt} is executed with a @code{tag}, matching this ideoms @code{tag}, then the @code{handler} will be executed with @code{handler_data} unified to,
@code{handler_data = [intag,next,kont,data_from_abort]}, The actual intag will be @code{intag}. A goal, @code{next()}, will be supplied which can be used to instruct the code to search for the next handler if executed. The actual continuation goal @code{kont}, is supplied as well as data send from the @code{abort_to_prompt} in @code{data_from_abort}. @code{kont} is a term with one argument and is executed like @code{call_k(kont,Arg)}, sending an @code{Arg} to the restart to the continuation. @code{kont} is live for the rest of the execution and the handler will at backtracking fail the whole @code{with_promt} ideom.
@code{call_k(kont,A)}, execute a continuation goal.
@code{abort_to_prompt(tag,data_to_handler, data_from_continuation)}, will abort with tag @code{tag}, for which a handler is searched. @code{data_to_handler}, is data sent to the handler, and @code{data_from_continuation}, is the data that is put inside the argument of the continuation.
@code{re_prompt(tag,kont,handle_data handle kont_data))}
@code{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.
@subsubsection Example:
(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,
/* 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),
/* transfers data from the producer to the feeder */
pr(F,S) :- next(F,X,FF) -> feed(S,X,SS), pr(FF,SS).
@end verbatim
@node prolog zip
@subsection Zip like constructs
@node prolog hash
@subsection Hash datastructure
@node prolog postpone
@subsection Postpone.
@node internals
@section Prolog internals
......@@ -58,9 +58,7 @@
(goal-eval handle))
(list data)))))
(define call_k
(([K X] X D (((<lookup> K)) D)))))
(define (call_k K D) (((<lookup> K)) D))
(compile-prolog-string "yield(X) :- abort_to_prompt(generator,X,_).")
(compile-prolog-string "eat(X) :- abort_to_prompt(generator,_,X).")
......@@ -96,21 +94,6 @@ run2 :- generator(iter2(0),F),pr2(F,_).
pr2(F,_) :- next(F,_,_),fail.
;; Example 3 (run3)
iter3(S,N) :- N < 10 -> (write(iter3(S,N)),nl,N2 is N + 1, iter3(S,N2)) ; true.
run3 :- generator((eat(X),iter3(X,X)),F),pr3(F).
pr3(F) :- call_k(F,_,0),write('--------'),nl,call_k(F,_,5).
;; Example 4 (run4)
iter4(S,N) :- N < 10 -> (write(iter4(S,N)),nl;N2 is N + 1, iter4(S,N2)).
run4 :- generator((eat(X),iter4(X,X)),F),pr4(F).
pr4(F) :- (call_k(F,_,0);call_k(F,_,5)),fail.
\ No newline at end of file
(define-module (logic guile-log guile-prolog interleave)
#:use-module (logic guile-log prolog goal-functors)
#:use-module (logic guile-log)
#:export (or_i and_i or_union))
(define-syntax-rule (mk-i or_i f)
(<define> (or_i . x)
(<let> ((x (map (lambda (x) (<lambda> () (goal-evel x))) x)))
(<apply> (@@ (logic guile-log interleave) f) x))))
(<let> ((x (map (lambda (x) (<lambda> () (goal-eval x))) x)))
((@@ (logic guile-log interleave) f) x))))
(mk-i or_i f-interleave)
(mk-i and_i and-interleave)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment