Execution of prolog code is sequential in nature, but one would like to be able to execute multiple algorithm in paralell. Turns out that swi's engine's are quite good att performing this task for us, we can fire up one engine per algorithm and generate answers back and let them sit there. This is a quite good solution and possible the one that we should stick to. But guile-log has a more general ideom, it looks like:
paralell(Goal1, ...,Goaln).
we will imply execute Goal1
in paralell and any back tracking back into it will generate a new solution without affecting the other paralell ones. Normal backtracking will skip paralell entirely. The idea is that to backtrack back into paralell we capture the fail P
via the fail(P)
goal. Using this we can construct.
pzip(Goal1,...,Goaln).
?- .2 pzip((X=1;X=2),(Y=3;Y=4)).
X=1
Y=3
X=2
Y=4
?-
You may find these ideoms in (logic guile-log guile-prolog paralell)
. Generally when a variable is bounn in both branches the result is that if one branch backtracks the binding in the other branch is lost. We will later try to solve this knot so for know don't try to unify the same variable in two or more branches. If you want safty from this bug please use engines in stead. So here is what can go wrong.
?- .2 pzip((X=1;X=2),(X=1,(Y=3;Y=4))).
X=1
Y=3
X=2 %wrong!!
Y=4
?-
Example, some gemetry, assume point lines in x direction or y directiln and simple rectangles built by those. Here is some code
% repr(f(g(X),Y),Out) -> Out = f(g(*),*)
%stall('P',P) will let P be visible to the shell prompt
stall_me(P) :-
repr(P,PP),
write('stalls (P): '), write(PP),nl,
stall('P',P),
fail.
%Asks a user for
ask_geo(A,Cur,Res,P) :-
write('current value or s: '),
write(Cur),nl,
ask('> ',Ask),
(
(Ask=s -> stall_me(P) ; (Ask=A,!,Res))
ask_geo(A,Cur,Res,P)
).
% default value is X, then a backtracker P is stored and
% transported to the continuation, if this fails we will
% ask for a new value
value(X,Y) :-
(Y=X,fail(P),cc(P)) ;
ask_geo(A,X,value(A,Y),*),
point(point(A,B),Y) :- !,
paralell(
[AP] <= value(A,AA),
[BP] <= value(B,BB)
),
(
(Y=point(AA,BB), fail(P), cc(point(P,AP,BP)) ;
ask_geo(X,point(A,B),point(X,Y),point(AP,BP)).
)
point(A,Y) :-
ask_geo(A,point(*,*),point(X,Y),*) -> true ; point(A,Y).
xline(xline(P1,P2), Y) :-
paralell(
[AP1] <= point(P1,PP1),
[AP2] <= point(P1,PP1)
),
(
PP1 = point(A1,B1),
PP2 = point(A2,B2),
(
(Y = xline(PP1,PP2), fail(P), cc(xline(P,AP1,AP2)));
ask_geo(X, xline(P1,P2), xline(X,Y), xline(AP1,AP2))
) => [Fail],
(
(A1 is A2,B1 < B2) ->
cc(Fail);
stall_me(Fail)
)
).
yline(yline(P1,P2), Y) :-
paralell(
[AP1] <= point(P1,PP1),
[AP2] <= point(P1,PP1)
),
(
PP1 = point(A1,B1),
PP2 = point(A2,B2),
(
(Y = yline(PP1,PP2), fail(P), cc(yline(P,AP1,AP2)));
ask_geo(X, yline(P1,P2), yline(X,Y), yline(AP1,AP2))
) => [Fail],
(
(A1 < A2, B1 is B2) ->
cc(Fail);
stall_me(Fail)
)
).
rect(rect(P1,P2), Y) :-
paralell(
[AP1] <= point(P1,PP1),
[AP2] <= point(P1,PP1)
),
(
PP1 = point(A1,B1),
PP2 = point(A2,B2),
(
(Y = rect(PP1,PP2), fail(P), cc(rect(P,AP1,AP2)));
ask_geo(X, rect(P1,P2), rect(X,Y), rect(AP1,AP2))
) => [Fail],
(
(A1 < A2, B1 < B2) ->
cc(Fail);
stall_me(Fail)
)
).
?- xline(xline(*,*),Y) => [Fail], stall_me(Fail).
current value or s: point(*,*)
> point(0,0)
current value or s: point(*,*)
> point(1,1)
stalls (P): xline(*,point(*,*,*), point(*,*,*))
?- P=xline(Fail,_,_), run_fail(Fail).
current value or s: xline(point(0,0),point(1,1))
> s
stalls (P): xline(point(*,*,*), point(*,*,*))
?- P=xline(Fail,_).
current value or s: point(0,0)
> point(1,0).
stalls (P): xline(*,point(*,*,*), point(*,*,*))
Y=xline(point(1,0),point(1,1)).
?-